diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/media/video/gspca/stv06xx | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'drivers/media/video/gspca/stv06xx')
-rw-r--r-- | drivers/media/video/gspca/stv06xx/Kconfig | 9 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/Makefile | 10 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx.c | 630 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx.h | 115 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c | 611 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h | 207 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c | 573 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h | 152 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx_sensor.h | 87 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx_st6422.c | 401 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx_st6422.h | 52 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c | 392 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h | 259 |
13 files changed, 3498 insertions, 0 deletions
diff --git a/drivers/media/video/gspca/stv06xx/Kconfig b/drivers/media/video/gspca/stv06xx/Kconfig new file mode 100644 index 00000000000..634ad38d9fb --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/Kconfig | |||
@@ -0,0 +1,9 @@ | |||
1 | config 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 00000000000..2f3c3a606ce --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | obj-$(CONFIG_USB_STV06XX) += gspca_stv06xx.o | ||
2 | |||
3 | gspca_stv06xx-objs := stv06xx.o \ | ||
4 | stv06xx_vv6410.o \ | ||
5 | stv06xx_hdcs.o \ | ||
6 | stv06xx_pb0100.o \ | ||
7 | stv06xx_st6422.o | ||
8 | |||
9 | EXTRA_CFLAGS += -Idrivers/media/video/gspca | ||
10 | |||
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c new file mode 100644 index 00000000000..abf1658fa33 --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/stv06xx.c | |||
@@ -0,0 +1,630 @@ | |||
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 <linux/input.h> | ||
31 | #include "stv06xx_sensor.h" | ||
32 | |||
33 | MODULE_AUTHOR("Erik Andrén"); | ||
34 | MODULE_DESCRIPTION("STV06XX USB Camera Driver"); | ||
35 | MODULE_LICENSE("GPL"); | ||
36 | |||
37 | static int dump_bridge; | ||
38 | static int dump_sensor; | ||
39 | |||
40 | int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data) | ||
41 | { | ||
42 | int err; | ||
43 | struct usb_device *udev = sd->gspca_dev.dev; | ||
44 | __u8 *buf = sd->gspca_dev.usb_buf; | ||
45 | u8 len = (i2c_data > 0xff) ? 2 : 1; | ||
46 | |||
47 | buf[0] = i2c_data & 0xff; | ||
48 | buf[1] = (i2c_data >> 8) & 0xff; | ||
49 | |||
50 | err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | ||
51 | 0x04, 0x40, address, 0, buf, len, | ||
52 | STV06XX_URB_MSG_TIMEOUT); | ||
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 | |||
60 | int 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, "Reading 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 */ | ||
80 | int 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 | |||
91 | static int stv06xx_write_sensor_finish(struct sd *sd) | ||
92 | { | ||
93 | int err = 0; | ||
94 | |||
95 | if (sd->bridge == BRIDGE_STV610) { | ||
96 | struct usb_device *udev = sd->gspca_dev.dev; | ||
97 | __u8 *buf = sd->gspca_dev.usb_buf; | ||
98 | |||
99 | buf[0] = 0; | ||
100 | err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | ||
101 | 0x04, 0x40, 0x1704, 0, buf, 1, | ||
102 | STV06XX_URB_MSG_TIMEOUT); | ||
103 | } | ||
104 | |||
105 | return (err < 0) ? err : 0; | ||
106 | } | ||
107 | |||
108 | int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len) | ||
109 | { | ||
110 | int err, i, j; | ||
111 | struct usb_device *udev = sd->gspca_dev.dev; | ||
112 | __u8 *buf = sd->gspca_dev.usb_buf; | ||
113 | |||
114 | PDEBUG(D_CONF, "I2C: Command buffer contains %d entries", len); | ||
115 | for (i = 0; i < len;) { | ||
116 | /* Build the command buffer */ | ||
117 | memset(buf, 0, I2C_BUFFER_LENGTH); | ||
118 | for (j = 0; j < I2C_MAX_BYTES && i < len; j++, i++) { | ||
119 | buf[j] = data[2*i]; | ||
120 | buf[0x10 + j] = data[2*i+1]; | ||
121 | PDEBUG(D_CONF, "I2C: Writing 0x%02x to reg 0x%02x", | ||
122 | data[2*i+1], data[2*i]); | ||
123 | } | ||
124 | buf[0x20] = sd->sensor->i2c_addr; | ||
125 | buf[0x21] = j - 1; /* Number of commands to send - 1 */ | ||
126 | buf[0x22] = I2C_WRITE_CMD; | ||
127 | err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | ||
128 | 0x04, 0x40, 0x0400, 0, buf, | ||
129 | I2C_BUFFER_LENGTH, | ||
130 | STV06XX_URB_MSG_TIMEOUT); | ||
131 | if (err < 0) | ||
132 | return err; | ||
133 | } | ||
134 | return stv06xx_write_sensor_finish(sd); | ||
135 | } | ||
136 | |||
137 | int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len) | ||
138 | { | ||
139 | int err, i, j; | ||
140 | struct usb_device *udev = sd->gspca_dev.dev; | ||
141 | __u8 *buf = sd->gspca_dev.usb_buf; | ||
142 | |||
143 | PDEBUG(D_CONF, "I2C: Command buffer contains %d entries", len); | ||
144 | |||
145 | for (i = 0; i < len;) { | ||
146 | /* Build the command buffer */ | ||
147 | memset(buf, 0, I2C_BUFFER_LENGTH); | ||
148 | for (j = 0; j < I2C_MAX_WORDS && i < len; j++, i++) { | ||
149 | buf[j] = data[2*i]; | ||
150 | buf[0x10 + j * 2] = data[2*i+1]; | ||
151 | buf[0x10 + j * 2 + 1] = data[2*i+1] >> 8; | ||
152 | PDEBUG(D_CONF, "I2C: Writing 0x%04x to reg 0x%02x", | ||
153 | data[2*i+1], data[2*i]); | ||
154 | } | ||
155 | buf[0x20] = sd->sensor->i2c_addr; | ||
156 | buf[0x21] = j - 1; /* Number of commands to send - 1 */ | ||
157 | buf[0x22] = I2C_WRITE_CMD; | ||
158 | err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | ||
159 | 0x04, 0x40, 0x0400, 0, buf, | ||
160 | I2C_BUFFER_LENGTH, | ||
161 | STV06XX_URB_MSG_TIMEOUT); | ||
162 | if (err < 0) | ||
163 | return err; | ||
164 | } | ||
165 | return stv06xx_write_sensor_finish(sd); | ||
166 | } | ||
167 | |||
168 | int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value) | ||
169 | { | ||
170 | int err; | ||
171 | struct usb_device *udev = sd->gspca_dev.dev; | ||
172 | __u8 *buf = sd->gspca_dev.usb_buf; | ||
173 | |||
174 | err = stv06xx_write_bridge(sd, STV_I2C_FLUSH, sd->sensor->i2c_flush); | ||
175 | if (err < 0) | ||
176 | return err; | ||
177 | |||
178 | /* Clear mem */ | ||
179 | memset(buf, 0, I2C_BUFFER_LENGTH); | ||
180 | |||
181 | buf[0] = address; | ||
182 | buf[0x20] = sd->sensor->i2c_addr; | ||
183 | buf[0x21] = 0; | ||
184 | |||
185 | /* Read I2C register */ | ||
186 | buf[0x22] = I2C_READ_CMD; | ||
187 | |||
188 | err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | ||
189 | 0x04, 0x40, 0x1400, 0, buf, I2C_BUFFER_LENGTH, | ||
190 | STV06XX_URB_MSG_TIMEOUT); | ||
191 | if (err < 0) { | ||
192 | err("I2C: Read error writing address: %d", err); | ||
193 | return err; | ||
194 | } | ||
195 | |||
196 | err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), | ||
197 | 0x04, 0xc0, 0x1410, 0, buf, sd->sensor->i2c_len, | ||
198 | STV06XX_URB_MSG_TIMEOUT); | ||
199 | if (sd->sensor->i2c_len == 2) | ||
200 | *value = buf[0] | (buf[1] << 8); | ||
201 | else | ||
202 | *value = buf[0]; | ||
203 | |||
204 | PDEBUG(D_CONF, "I2C: Read 0x%x from address 0x%x, status: %d", | ||
205 | *value, address, err); | ||
206 | |||
207 | return (err < 0) ? err : 0; | ||
208 | } | ||
209 | |||
210 | /* Dumps all bridge registers */ | ||
211 | static void stv06xx_dump_bridge(struct sd *sd) | ||
212 | { | ||
213 | int i; | ||
214 | u8 data, buf; | ||
215 | |||
216 | info("Dumping all stv06xx bridge registers"); | ||
217 | for (i = 0x1400; i < 0x160f; i++) { | ||
218 | stv06xx_read_bridge(sd, i, &data); | ||
219 | |||
220 | info("Read 0x%x from address 0x%x", data, i); | ||
221 | } | ||
222 | |||
223 | info("Testing stv06xx bridge registers for writability"); | ||
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 */ | ||
243 | static 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 && sd->sensor->dump) | ||
257 | sd->sensor->dump(sd); | ||
258 | |||
259 | return (err < 0) ? err : 0; | ||
260 | } | ||
261 | |||
262 | /* Start the camera */ | ||
263 | static int stv06xx_start(struct gspca_dev *gspca_dev) | ||
264 | { | ||
265 | struct sd *sd = (struct sd *) gspca_dev; | ||
266 | struct usb_host_interface *alt; | ||
267 | struct usb_interface *intf; | ||
268 | int err, packet_size; | ||
269 | |||
270 | intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); | ||
271 | alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); | ||
272 | if (!alt) { | ||
273 | PDEBUG(D_ERR, "Couldn't get altsetting"); | ||
274 | return -EIO; | ||
275 | } | ||
276 | |||
277 | packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); | ||
278 | err = stv06xx_write_bridge(sd, STV_ISO_SIZE_L, packet_size); | ||
279 | if (err < 0) | ||
280 | return err; | ||
281 | |||
282 | /* Prepare the sensor for start */ | ||
283 | err = sd->sensor->start(sd); | ||
284 | if (err < 0) | ||
285 | goto out; | ||
286 | |||
287 | /* Start isochronous streaming */ | ||
288 | err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 1); | ||
289 | |||
290 | out: | ||
291 | if (err < 0) | ||
292 | PDEBUG(D_STREAM, "Starting stream failed"); | ||
293 | else | ||
294 | PDEBUG(D_STREAM, "Started streaming"); | ||
295 | |||
296 | return (err < 0) ? err : 0; | ||
297 | } | ||
298 | |||
299 | static int stv06xx_isoc_init(struct gspca_dev *gspca_dev) | ||
300 | { | ||
301 | struct usb_host_interface *alt; | ||
302 | struct sd *sd = (struct sd *) gspca_dev; | ||
303 | |||
304 | /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ | ||
305 | alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; | ||
306 | alt->endpoint[0].desc.wMaxPacketSize = | ||
307 | cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]); | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static int stv06xx_isoc_nego(struct gspca_dev *gspca_dev) | ||
313 | { | ||
314 | int ret, packet_size, min_packet_size; | ||
315 | struct usb_host_interface *alt; | ||
316 | struct sd *sd = (struct sd *) gspca_dev; | ||
317 | |||
318 | alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; | ||
319 | packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); | ||
320 | min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode]; | ||
321 | if (packet_size <= min_packet_size) | ||
322 | return -EIO; | ||
323 | |||
324 | packet_size -= 100; | ||
325 | if (packet_size < min_packet_size) | ||
326 | packet_size = min_packet_size; | ||
327 | alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(packet_size); | ||
328 | |||
329 | ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); | ||
330 | if (ret < 0) | ||
331 | PDEBUG(D_ERR|D_STREAM, "set alt 1 err %d", ret); | ||
332 | |||
333 | return ret; | ||
334 | } | ||
335 | |||
336 | static void stv06xx_stopN(struct gspca_dev *gspca_dev) | ||
337 | { | ||
338 | int err; | ||
339 | struct sd *sd = (struct sd *) gspca_dev; | ||
340 | |||
341 | /* stop ISO-streaming */ | ||
342 | err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 0); | ||
343 | if (err < 0) | ||
344 | goto out; | ||
345 | |||
346 | err = sd->sensor->stop(sd); | ||
347 | |||
348 | out: | ||
349 | if (err < 0) | ||
350 | PDEBUG(D_STREAM, "Failed to stop stream"); | ||
351 | else | ||
352 | PDEBUG(D_STREAM, "Stopped streaming"); | ||
353 | } | ||
354 | |||
355 | /* | ||
356 | * Analyse an USB packet of the data stream and store it appropriately. | ||
357 | * Each packet contains an integral number of chunks. Each chunk has | ||
358 | * 2-bytes identification, followed by 2-bytes that describe the chunk | ||
359 | * length. Known/guessed chunk identifications are: | ||
360 | * 8001/8005/C001/C005 - Begin new frame | ||
361 | * 8002/8006/C002/C006 - End frame | ||
362 | * 0200/4200 - Contains actual image data, bayer or compressed | ||
363 | * 0005 - 11 bytes of unknown data | ||
364 | * 0100 - 2 bytes of unknown data | ||
365 | * The 0005 and 0100 chunks seem to appear only in compressed stream. | ||
366 | */ | ||
367 | static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev, | ||
368 | u8 *data, /* isoc packet */ | ||
369 | int len) /* iso packet length */ | ||
370 | { | ||
371 | struct sd *sd = (struct sd *) gspca_dev; | ||
372 | |||
373 | PDEBUG(D_PACK, "Packet of length %d arrived", len); | ||
374 | |||
375 | /* A packet may contain several frames | ||
376 | loop until the whole packet is reached */ | ||
377 | while (len) { | ||
378 | int id, chunk_len; | ||
379 | |||
380 | if (len < 4) { | ||
381 | PDEBUG(D_PACK, "Packet is smaller than 4 bytes"); | ||
382 | return; | ||
383 | } | ||
384 | |||
385 | /* Capture the id */ | ||
386 | id = (data[0] << 8) | data[1]; | ||
387 | |||
388 | /* Capture the chunk length */ | ||
389 | chunk_len = (data[2] << 8) | data[3]; | ||
390 | PDEBUG(D_PACK, "Chunk id: %x, length: %d", id, chunk_len); | ||
391 | |||
392 | data += 4; | ||
393 | len -= 4; | ||
394 | |||
395 | if (len < chunk_len) { | ||
396 | PDEBUG(D_ERR, "URB packet length is smaller" | ||
397 | " than the specified chunk length"); | ||
398 | gspca_dev->last_packet_type = DISCARD_PACKET; | ||
399 | return; | ||
400 | } | ||
401 | |||
402 | /* First byte seem to be 02=data 2nd byte is unknown??? */ | ||
403 | if (sd->bridge == BRIDGE_ST6422 && (id & 0xff00) == 0x0200) | ||
404 | goto frame_data; | ||
405 | |||
406 | switch (id) { | ||
407 | case 0x0200: | ||
408 | case 0x4200: | ||
409 | frame_data: | ||
410 | PDEBUG(D_PACK, "Frame data packet detected"); | ||
411 | |||
412 | if (sd->to_skip) { | ||
413 | int skip = (sd->to_skip < chunk_len) ? | ||
414 | sd->to_skip : chunk_len; | ||
415 | data += skip; | ||
416 | len -= skip; | ||
417 | chunk_len -= skip; | ||
418 | sd->to_skip -= skip; | ||
419 | } | ||
420 | |||
421 | gspca_frame_add(gspca_dev, INTER_PACKET, | ||
422 | data, chunk_len); | ||
423 | break; | ||
424 | |||
425 | case 0x8001: | ||
426 | case 0x8005: | ||
427 | case 0xc001: | ||
428 | case 0xc005: | ||
429 | PDEBUG(D_PACK, "Starting new frame"); | ||
430 | |||
431 | /* Create a new frame, chunk length should be zero */ | ||
432 | gspca_frame_add(gspca_dev, FIRST_PACKET, | ||
433 | NULL, 0); | ||
434 | |||
435 | if (sd->bridge == BRIDGE_ST6422) | ||
436 | sd->to_skip = gspca_dev->width * 4; | ||
437 | |||
438 | if (chunk_len) | ||
439 | PDEBUG(D_ERR, "Chunk length is " | ||
440 | "non-zero on a SOF"); | ||
441 | break; | ||
442 | |||
443 | case 0x8002: | ||
444 | case 0x8006: | ||
445 | case 0xc002: | ||
446 | PDEBUG(D_PACK, "End of frame detected"); | ||
447 | |||
448 | /* Complete the last frame (if any) */ | ||
449 | gspca_frame_add(gspca_dev, LAST_PACKET, | ||
450 | NULL, 0); | ||
451 | |||
452 | if (chunk_len) | ||
453 | PDEBUG(D_ERR, "Chunk length is " | ||
454 | "non-zero on a EOF"); | ||
455 | break; | ||
456 | |||
457 | case 0x0005: | ||
458 | PDEBUG(D_PACK, "Chunk 0x005 detected"); | ||
459 | /* Unknown chunk with 11 bytes of data, | ||
460 | occurs just before end of each frame | ||
461 | in compressed mode */ | ||
462 | break; | ||
463 | |||
464 | case 0x0100: | ||
465 | PDEBUG(D_PACK, "Chunk 0x0100 detected"); | ||
466 | /* Unknown chunk with 2 bytes of data, | ||
467 | occurs 2-3 times per USB interrupt */ | ||
468 | break; | ||
469 | case 0x42ff: | ||
470 | PDEBUG(D_PACK, "Chunk 0x42ff detected"); | ||
471 | /* Special chunk seen sometimes on the ST6422 */ | ||
472 | break; | ||
473 | default: | ||
474 | PDEBUG(D_PACK, "Unknown chunk 0x%04x detected", id); | ||
475 | /* Unknown chunk */ | ||
476 | } | ||
477 | data += chunk_len; | ||
478 | len -= chunk_len; | ||
479 | } | ||
480 | } | ||
481 | |||
482 | #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) | ||
483 | static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, | ||
484 | u8 *data, /* interrupt packet data */ | ||
485 | int len) /* interrupt packet length */ | ||
486 | { | ||
487 | int ret = -EINVAL; | ||
488 | |||
489 | if (len == 1 && data[0] == 0x80) { | ||
490 | input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); | ||
491 | input_sync(gspca_dev->input_dev); | ||
492 | ret = 0; | ||
493 | } | ||
494 | |||
495 | if (len == 1 && data[0] == 0x88) { | ||
496 | input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); | ||
497 | input_sync(gspca_dev->input_dev); | ||
498 | ret = 0; | ||
499 | } | ||
500 | |||
501 | return ret; | ||
502 | } | ||
503 | #endif | ||
504 | |||
505 | static int stv06xx_config(struct gspca_dev *gspca_dev, | ||
506 | const struct usb_device_id *id); | ||
507 | |||
508 | /* sub-driver description */ | ||
509 | static const struct sd_desc sd_desc = { | ||
510 | .name = MODULE_NAME, | ||
511 | .config = stv06xx_config, | ||
512 | .init = stv06xx_init, | ||
513 | .start = stv06xx_start, | ||
514 | .stopN = stv06xx_stopN, | ||
515 | .pkt_scan = stv06xx_pkt_scan, | ||
516 | .isoc_init = stv06xx_isoc_init, | ||
517 | .isoc_nego = stv06xx_isoc_nego, | ||
518 | #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) | ||
519 | .int_pkt_scan = sd_int_pkt_scan, | ||
520 | #endif | ||
521 | }; | ||
522 | |||
523 | /* This function is called at probe time */ | ||
524 | static int stv06xx_config(struct gspca_dev *gspca_dev, | ||
525 | const struct usb_device_id *id) | ||
526 | { | ||
527 | struct sd *sd = (struct sd *) gspca_dev; | ||
528 | |||
529 | PDEBUG(D_PROBE, "Configuring camera"); | ||
530 | |||
531 | sd->desc = sd_desc; | ||
532 | sd->bridge = id->driver_info; | ||
533 | gspca_dev->sd_desc = &sd->desc; | ||
534 | |||
535 | if (dump_bridge) | ||
536 | stv06xx_dump_bridge(sd); | ||
537 | |||
538 | sd->sensor = &stv06xx_sensor_st6422; | ||
539 | if (!sd->sensor->probe(sd)) | ||
540 | return 0; | ||
541 | |||
542 | sd->sensor = &stv06xx_sensor_vv6410; | ||
543 | if (!sd->sensor->probe(sd)) | ||
544 | return 0; | ||
545 | |||
546 | sd->sensor = &stv06xx_sensor_hdcs1x00; | ||
547 | if (!sd->sensor->probe(sd)) | ||
548 | return 0; | ||
549 | |||
550 | sd->sensor = &stv06xx_sensor_hdcs1020; | ||
551 | if (!sd->sensor->probe(sd)) | ||
552 | return 0; | ||
553 | |||
554 | sd->sensor = &stv06xx_sensor_pb0100; | ||
555 | if (!sd->sensor->probe(sd)) | ||
556 | return 0; | ||
557 | |||
558 | sd->sensor = NULL; | ||
559 | return -ENODEV; | ||
560 | } | ||
561 | |||
562 | |||
563 | |||
564 | /* -- module initialisation -- */ | ||
565 | static const struct usb_device_id device_table[] = { | ||
566 | /* QuickCam Express */ | ||
567 | {USB_DEVICE(0x046d, 0x0840), .driver_info = BRIDGE_STV600 }, | ||
568 | /* LEGO cam / QuickCam Web */ | ||
569 | {USB_DEVICE(0x046d, 0x0850), .driver_info = BRIDGE_STV610 }, | ||
570 | /* Dexxa WebCam USB */ | ||
571 | {USB_DEVICE(0x046d, 0x0870), .driver_info = BRIDGE_STV602 }, | ||
572 | /* QuickCam Messenger */ | ||
573 | {USB_DEVICE(0x046D, 0x08F0), .driver_info = BRIDGE_ST6422 }, | ||
574 | /* QuickCam Communicate */ | ||
575 | {USB_DEVICE(0x046D, 0x08F5), .driver_info = BRIDGE_ST6422 }, | ||
576 | /* QuickCam Messenger (new) */ | ||
577 | {USB_DEVICE(0x046D, 0x08F6), .driver_info = BRIDGE_ST6422 }, | ||
578 | {} | ||
579 | }; | ||
580 | MODULE_DEVICE_TABLE(usb, device_table); | ||
581 | |||
582 | /* -- device connect -- */ | ||
583 | static int sd_probe(struct usb_interface *intf, | ||
584 | const struct usb_device_id *id) | ||
585 | { | ||
586 | PDEBUG(D_PROBE, "Probing for a stv06xx device"); | ||
587 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | ||
588 | THIS_MODULE); | ||
589 | } | ||
590 | |||
591 | static void sd_disconnect(struct usb_interface *intf) | ||
592 | { | ||
593 | struct gspca_dev *gspca_dev = usb_get_intfdata(intf); | ||
594 | struct sd *sd = (struct sd *) gspca_dev; | ||
595 | PDEBUG(D_PROBE, "Disconnecting the stv06xx device"); | ||
596 | |||
597 | if (sd->sensor->disconnect) | ||
598 | sd->sensor->disconnect(sd); | ||
599 | gspca_disconnect(intf); | ||
600 | } | ||
601 | |||
602 | static struct usb_driver sd_driver = { | ||
603 | .name = MODULE_NAME, | ||
604 | .id_table = device_table, | ||
605 | .probe = sd_probe, | ||
606 | .disconnect = sd_disconnect, | ||
607 | #ifdef CONFIG_PM | ||
608 | .suspend = gspca_suspend, | ||
609 | .resume = gspca_resume, | ||
610 | #endif | ||
611 | }; | ||
612 | |||
613 | /* -- module insert / remove -- */ | ||
614 | static int __init sd_mod_init(void) | ||
615 | { | ||
616 | return usb_register(&sd_driver); | ||
617 | } | ||
618 | static void __exit sd_mod_exit(void) | ||
619 | { | ||
620 | usb_deregister(&sd_driver); | ||
621 | } | ||
622 | |||
623 | module_init(sd_mod_init); | ||
624 | module_exit(sd_mod_exit); | ||
625 | |||
626 | module_param(dump_bridge, bool, S_IRUGO | S_IWUSR); | ||
627 | MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup"); | ||
628 | |||
629 | module_param(dump_sensor, bool, S_IRUGO | S_IWUSR); | ||
630 | MODULE_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 00000000000..e0f63c51f40 --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/stv06xx.h | |||
@@ -0,0 +1,115 @@ | |||
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 <linux/slab.h> | ||
34 | #include "gspca.h" | ||
35 | |||
36 | #define MODULE_NAME "STV06xx" | ||
37 | |||
38 | #define STV_ISOC_ENDPOINT_ADDR 0x81 | ||
39 | |||
40 | #define STV_REG23 0x0423 | ||
41 | |||
42 | /* Control registers of the STV0600 ASIC */ | ||
43 | #define STV_I2C_PARTNER 0x1420 | ||
44 | #define STV_I2C_VAL_REG_VAL_PAIRS_MIN1 0x1421 | ||
45 | #define STV_I2C_READ_WRITE_TOGGLE 0x1422 | ||
46 | #define STV_I2C_FLUSH 0x1423 | ||
47 | #define STV_I2C_SUCC_READ_REG_VALS 0x1424 | ||
48 | |||
49 | #define STV_ISO_ENABLE 0x1440 | ||
50 | #define STV_SCAN_RATE 0x1443 | ||
51 | #define STV_LED_CTRL 0x1445 | ||
52 | #define STV_STV0600_EMULATION 0x1446 | ||
53 | #define STV_REG00 0x1500 | ||
54 | #define STV_REG01 0x1501 | ||
55 | #define STV_REG02 0x1502 | ||
56 | #define STV_REG03 0x1503 | ||
57 | #define STV_REG04 0x1504 | ||
58 | |||
59 | #define STV_ISO_SIZE_L 0x15c1 | ||
60 | #define STV_ISO_SIZE_H 0x15c2 | ||
61 | |||
62 | /* Refers to the CIF 352x288 and QCIF 176x144 */ | ||
63 | /* 1: 288 lines, 2: 144 lines */ | ||
64 | #define STV_Y_CTRL 0x15c3 | ||
65 | |||
66 | /* 0xa: 352 columns, 0x6: 176 columns */ | ||
67 | #define STV_X_CTRL 0x1680 | ||
68 | |||
69 | #define STV06XX_URB_MSG_TIMEOUT 5000 | ||
70 | |||
71 | #define I2C_MAX_BYTES 16 | ||
72 | #define I2C_MAX_WORDS 8 | ||
73 | |||
74 | #define I2C_BUFFER_LENGTH 0x23 | ||
75 | #define I2C_READ_CMD 3 | ||
76 | #define I2C_WRITE_CMD 1 | ||
77 | |||
78 | #define LED_ON 1 | ||
79 | #define LED_OFF 0 | ||
80 | |||
81 | /* STV06xx device descriptor */ | ||
82 | struct sd { | ||
83 | struct gspca_dev gspca_dev; | ||
84 | |||
85 | /* A pointer to the currently connected sensor */ | ||
86 | const struct stv06xx_sensor *sensor; | ||
87 | |||
88 | /* A pointer to the sd_desc struct */ | ||
89 | struct sd_desc desc; | ||
90 | |||
91 | /* Sensor private data */ | ||
92 | void *sensor_priv; | ||
93 | |||
94 | /* The first 4 lines produced by the stv6422 are no good, this keeps | ||
95 | track of how many bytes we still need to skip during a frame */ | ||
96 | int to_skip; | ||
97 | |||
98 | /* Bridge / Camera type */ | ||
99 | u8 bridge; | ||
100 | #define BRIDGE_STV600 0 | ||
101 | #define BRIDGE_STV602 1 | ||
102 | #define BRIDGE_STV610 2 | ||
103 | #define BRIDGE_ST6422 3 /* With integrated sensor */ | ||
104 | }; | ||
105 | |||
106 | int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data); | ||
107 | int stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data); | ||
108 | |||
109 | int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len); | ||
110 | int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len); | ||
111 | |||
112 | int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value); | ||
113 | int stv06xx_write_sensor(struct sd *sd, u8 address, u16 value); | ||
114 | |||
115 | #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 00000000000..b8156855f2b --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c | |||
@@ -0,0 +1,611 @@ | |||
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 | |||
33 | static const struct ctrl hdcs1x00_ctrl[] = { | ||
34 | { | ||
35 | { | ||
36 | .id = V4L2_CID_EXPOSURE, | ||
37 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
38 | .name = "exposure", | ||
39 | .minimum = 0x00, | ||
40 | .maximum = 0xff, | ||
41 | .step = 0x1, | ||
42 | .default_value = HDCS_DEFAULT_EXPOSURE, | ||
43 | .flags = V4L2_CTRL_FLAG_SLIDER | ||
44 | }, | ||
45 | .set = hdcs_set_exposure, | ||
46 | .get = hdcs_get_exposure | ||
47 | }, { | ||
48 | { | ||
49 | .id = V4L2_CID_GAIN, | ||
50 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
51 | .name = "gain", | ||
52 | .minimum = 0x00, | ||
53 | .maximum = 0xff, | ||
54 | .step = 0x1, | ||
55 | .default_value = HDCS_DEFAULT_GAIN, | ||
56 | .flags = V4L2_CTRL_FLAG_SLIDER | ||
57 | }, | ||
58 | .set = hdcs_set_gain, | ||
59 | .get = hdcs_get_gain | ||
60 | } | ||
61 | }; | ||
62 | |||
63 | static struct v4l2_pix_format hdcs1x00_mode[] = { | ||
64 | { | ||
65 | HDCS_1X00_DEF_WIDTH, | ||
66 | HDCS_1X00_DEF_HEIGHT, | ||
67 | V4L2_PIX_FMT_SGRBG8, | ||
68 | V4L2_FIELD_NONE, | ||
69 | .sizeimage = | ||
70 | HDCS_1X00_DEF_WIDTH * HDCS_1X00_DEF_HEIGHT, | ||
71 | .bytesperline = HDCS_1X00_DEF_WIDTH, | ||
72 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
73 | .priv = 1 | ||
74 | } | ||
75 | }; | ||
76 | |||
77 | static const struct ctrl hdcs1020_ctrl[] = { | ||
78 | { | ||
79 | { | ||
80 | .id = V4L2_CID_EXPOSURE, | ||
81 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
82 | .name = "exposure", | ||
83 | .minimum = 0x00, | ||
84 | .maximum = 0xffff, | ||
85 | .step = 0x1, | ||
86 | .default_value = HDCS_DEFAULT_EXPOSURE, | ||
87 | .flags = V4L2_CTRL_FLAG_SLIDER | ||
88 | }, | ||
89 | .set = hdcs_set_exposure, | ||
90 | .get = hdcs_get_exposure | ||
91 | }, { | ||
92 | { | ||
93 | .id = V4L2_CID_GAIN, | ||
94 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
95 | .name = "gain", | ||
96 | .minimum = 0x00, | ||
97 | .maximum = 0xff, | ||
98 | .step = 0x1, | ||
99 | .default_value = HDCS_DEFAULT_GAIN, | ||
100 | .flags = V4L2_CTRL_FLAG_SLIDER | ||
101 | }, | ||
102 | .set = hdcs_set_gain, | ||
103 | .get = hdcs_get_gain | ||
104 | } | ||
105 | }; | ||
106 | |||
107 | static struct v4l2_pix_format hdcs1020_mode[] = { | ||
108 | { | ||
109 | HDCS_1020_DEF_WIDTH, | ||
110 | HDCS_1020_DEF_HEIGHT, | ||
111 | V4L2_PIX_FMT_SGRBG8, | ||
112 | V4L2_FIELD_NONE, | ||
113 | .sizeimage = | ||
114 | HDCS_1020_DEF_WIDTH * HDCS_1020_DEF_HEIGHT, | ||
115 | .bytesperline = HDCS_1020_DEF_WIDTH, | ||
116 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
117 | .priv = 1 | ||
118 | } | ||
119 | }; | ||
120 | |||
121 | enum hdcs_power_state { | ||
122 | HDCS_STATE_SLEEP, | ||
123 | HDCS_STATE_IDLE, | ||
124 | HDCS_STATE_RUN | ||
125 | }; | ||
126 | |||
127 | /* no lock? */ | ||
128 | struct hdcs { | ||
129 | enum hdcs_power_state state; | ||
130 | int w, h; | ||
131 | |||
132 | /* visible area of the sensor array */ | ||
133 | struct { | ||
134 | int left, top; | ||
135 | int width, height; | ||
136 | int border; | ||
137 | } array; | ||
138 | |||
139 | struct { | ||
140 | /* Column timing overhead */ | ||
141 | u8 cto; | ||
142 | /* Column processing overhead */ | ||
143 | u8 cpo; | ||
144 | /* Row sample period constant */ | ||
145 | u16 rs; | ||
146 | /* Exposure reset duration */ | ||
147 | u16 er; | ||
148 | } exp; | ||
149 | |||
150 | int psmp; | ||
151 | u8 exp_cache, gain_cache; | ||
152 | }; | ||
153 | |||
154 | static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len) | ||
155 | { | ||
156 | u8 regs[I2C_MAX_BYTES * 2]; | ||
157 | int i; | ||
158 | |||
159 | if (unlikely((len <= 0) || (len >= I2C_MAX_BYTES) || | ||
160 | (reg + len > 0xff))) | ||
161 | return -EINVAL; | ||
162 | |||
163 | for (i = 0; i < len; i++) { | ||
164 | regs[2 * i] = reg; | ||
165 | regs[2 * i + 1] = vals[i]; | ||
166 | /* All addresses are shifted left one bit | ||
167 | * as bit 0 toggles r/w */ | ||
168 | reg += 2; | ||
169 | } | ||
170 | |||
171 | return stv06xx_write_sensor_bytes(sd, regs, len); | ||
172 | } | ||
173 | |||
174 | static int hdcs_set_state(struct sd *sd, enum hdcs_power_state state) | ||
175 | { | ||
176 | struct hdcs *hdcs = sd->sensor_priv; | ||
177 | u8 val; | ||
178 | int ret; | ||
179 | |||
180 | if (hdcs->state == state) | ||
181 | return 0; | ||
182 | |||
183 | /* we need to go idle before running or sleeping */ | ||
184 | if (hdcs->state != HDCS_STATE_IDLE) { | ||
185 | ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0); | ||
186 | if (ret) | ||
187 | return ret; | ||
188 | } | ||
189 | |||
190 | hdcs->state = HDCS_STATE_IDLE; | ||
191 | |||
192 | if (state == HDCS_STATE_IDLE) | ||
193 | return 0; | ||
194 | |||
195 | switch (state) { | ||
196 | case HDCS_STATE_SLEEP: | ||
197 | val = HDCS_SLEEP_MODE; | ||
198 | break; | ||
199 | |||
200 | case HDCS_STATE_RUN: | ||
201 | val = HDCS_RUN_ENABLE; | ||
202 | break; | ||
203 | |||
204 | default: | ||
205 | return -EINVAL; | ||
206 | } | ||
207 | |||
208 | ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), val); | ||
209 | |||
210 | /* Update the state if the write succeeded */ | ||
211 | if (!ret) | ||
212 | hdcs->state = state; | ||
213 | |||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | static int hdcs_reset(struct sd *sd) | ||
218 | { | ||
219 | struct hdcs *hdcs = sd->sensor_priv; | ||
220 | int err; | ||
221 | |||
222 | err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 1); | ||
223 | if (err < 0) | ||
224 | return err; | ||
225 | |||
226 | err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0); | ||
227 | if (err < 0) | ||
228 | hdcs->state = HDCS_STATE_IDLE; | ||
229 | |||
230 | return err; | ||
231 | } | ||
232 | |||
233 | static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) | ||
234 | { | ||
235 | struct sd *sd = (struct sd *) gspca_dev; | ||
236 | struct hdcs *hdcs = sd->sensor_priv; | ||
237 | |||
238 | *val = hdcs->exp_cache; | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val) | ||
244 | { | ||
245 | struct sd *sd = (struct sd *) gspca_dev; | ||
246 | struct hdcs *hdcs = sd->sensor_priv; | ||
247 | int rowexp, srowexp; | ||
248 | int max_srowexp; | ||
249 | /* Column time period */ | ||
250 | int ct; | ||
251 | /* Column processing period */ | ||
252 | int cp; | ||
253 | /* Row processing period */ | ||
254 | int rp; | ||
255 | /* Minimum number of column timing periods | ||
256 | within the column processing period */ | ||
257 | int mnct; | ||
258 | int cycles, err; | ||
259 | u8 exp[14]; | ||
260 | |||
261 | val &= 0xff; | ||
262 | hdcs->exp_cache = val; | ||
263 | |||
264 | cycles = val * HDCS_CLK_FREQ_MHZ * 257; | ||
265 | |||
266 | ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2); | ||
267 | cp = hdcs->exp.cto + (hdcs->w * ct / 2); | ||
268 | |||
269 | /* the cycles one row takes */ | ||
270 | rp = hdcs->exp.rs + cp; | ||
271 | |||
272 | rowexp = cycles / rp; | ||
273 | |||
274 | /* the remaining cycles */ | ||
275 | cycles -= rowexp * rp; | ||
276 | |||
277 | /* calculate sub-row exposure */ | ||
278 | if (IS_1020(sd)) { | ||
279 | /* see HDCS-1020 datasheet 3.5.6.4, p. 63 */ | ||
280 | srowexp = hdcs->w - (cycles + hdcs->exp.er + 13) / ct; | ||
281 | |||
282 | mnct = (hdcs->exp.er + 12 + ct - 1) / ct; | ||
283 | max_srowexp = hdcs->w - mnct; | ||
284 | } else { | ||
285 | /* see HDCS-1000 datasheet 3.4.5.5, p. 61 */ | ||
286 | srowexp = cp - hdcs->exp.er - 6 - cycles; | ||
287 | |||
288 | mnct = (hdcs->exp.er + 5 + ct - 1) / ct; | ||
289 | max_srowexp = cp - mnct * ct - 1; | ||
290 | } | ||
291 | |||
292 | if (srowexp < 0) | ||
293 | srowexp = 0; | ||
294 | else if (srowexp > max_srowexp) | ||
295 | srowexp = max_srowexp; | ||
296 | |||
297 | if (IS_1020(sd)) { | ||
298 | exp[0] = HDCS20_CONTROL; | ||
299 | exp[1] = 0x00; /* Stop streaming */ | ||
300 | exp[2] = HDCS_ROWEXPL; | ||
301 | exp[3] = rowexp & 0xff; | ||
302 | exp[4] = HDCS_ROWEXPH; | ||
303 | exp[5] = rowexp >> 8; | ||
304 | exp[6] = HDCS20_SROWEXP; | ||
305 | exp[7] = (srowexp >> 2) & 0xff; | ||
306 | exp[8] = HDCS20_ERROR; | ||
307 | exp[9] = 0x10; /* Clear exposure error flag*/ | ||
308 | exp[10] = HDCS20_CONTROL; | ||
309 | exp[11] = 0x04; /* Restart streaming */ | ||
310 | err = stv06xx_write_sensor_bytes(sd, exp, 6); | ||
311 | } else { | ||
312 | exp[0] = HDCS00_CONTROL; | ||
313 | exp[1] = 0x00; /* Stop streaming */ | ||
314 | exp[2] = HDCS_ROWEXPL; | ||
315 | exp[3] = rowexp & 0xff; | ||
316 | exp[4] = HDCS_ROWEXPH; | ||
317 | exp[5] = rowexp >> 8; | ||
318 | exp[6] = HDCS00_SROWEXPL; | ||
319 | exp[7] = srowexp & 0xff; | ||
320 | exp[8] = HDCS00_SROWEXPH; | ||
321 | exp[9] = srowexp >> 8; | ||
322 | exp[10] = HDCS_STATUS; | ||
323 | exp[11] = 0x10; /* Clear exposure error flag*/ | ||
324 | exp[12] = HDCS00_CONTROL; | ||
325 | exp[13] = 0x04; /* Restart streaming */ | ||
326 | err = stv06xx_write_sensor_bytes(sd, exp, 7); | ||
327 | if (err < 0) | ||
328 | return err; | ||
329 | } | ||
330 | PDEBUG(D_V4L2, "Writing exposure %d, rowexp %d, srowexp %d", | ||
331 | val, rowexp, srowexp); | ||
332 | return err; | ||
333 | } | ||
334 | |||
335 | static int hdcs_set_gains(struct sd *sd, u8 g) | ||
336 | { | ||
337 | struct hdcs *hdcs = sd->sensor_priv; | ||
338 | int err; | ||
339 | u8 gains[4]; | ||
340 | |||
341 | hdcs->gain_cache = g; | ||
342 | |||
343 | /* the voltage gain Av = (1 + 19 * val / 127) * (1 + bit7) */ | ||
344 | if (g > 127) | ||
345 | g = 0x80 | (g / 2); | ||
346 | |||
347 | gains[0] = g; | ||
348 | gains[1] = g; | ||
349 | gains[2] = g; | ||
350 | gains[3] = g; | ||
351 | |||
352 | err = hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4); | ||
353 | return err; | ||
354 | } | ||
355 | |||
356 | static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val) | ||
357 | { | ||
358 | struct sd *sd = (struct sd *) gspca_dev; | ||
359 | struct hdcs *hdcs = sd->sensor_priv; | ||
360 | |||
361 | *val = hdcs->gain_cache; | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val) | ||
367 | { | ||
368 | PDEBUG(D_V4L2, "Writing gain %d", val); | ||
369 | return hdcs_set_gains((struct sd *) gspca_dev, | ||
370 | val & 0xff); | ||
371 | } | ||
372 | |||
373 | static int hdcs_set_size(struct sd *sd, | ||
374 | unsigned int width, unsigned int height) | ||
375 | { | ||
376 | struct hdcs *hdcs = sd->sensor_priv; | ||
377 | u8 win[4]; | ||
378 | unsigned int x, y; | ||
379 | int err; | ||
380 | |||
381 | /* must be multiple of 4 */ | ||
382 | width = (width + 3) & ~0x3; | ||
383 | height = (height + 3) & ~0x3; | ||
384 | |||
385 | if (width > hdcs->array.width) | ||
386 | width = hdcs->array.width; | ||
387 | |||
388 | if (IS_1020(sd)) { | ||
389 | /* the borders are also invalid */ | ||
390 | if (height + 2 * hdcs->array.border + HDCS_1020_BOTTOM_Y_SKIP | ||
391 | > hdcs->array.height) | ||
392 | height = hdcs->array.height - 2 * hdcs->array.border - | ||
393 | HDCS_1020_BOTTOM_Y_SKIP; | ||
394 | |||
395 | y = (hdcs->array.height - HDCS_1020_BOTTOM_Y_SKIP - height) / 2 | ||
396 | + hdcs->array.top; | ||
397 | } else { | ||
398 | if (height > hdcs->array.height) | ||
399 | height = hdcs->array.height; | ||
400 | |||
401 | y = hdcs->array.top + (hdcs->array.height - height) / 2; | ||
402 | } | ||
403 | |||
404 | x = hdcs->array.left + (hdcs->array.width - width) / 2; | ||
405 | |||
406 | win[0] = y / 4; | ||
407 | win[1] = x / 4; | ||
408 | win[2] = (y + height) / 4 - 1; | ||
409 | win[3] = (x + width) / 4 - 1; | ||
410 | |||
411 | err = hdcs_reg_write_seq(sd, HDCS_FWROW, win, 4); | ||
412 | if (err < 0) | ||
413 | return err; | ||
414 | |||
415 | /* Update the current width and height */ | ||
416 | hdcs->w = width; | ||
417 | hdcs->h = height; | ||
418 | return err; | ||
419 | } | ||
420 | |||
421 | static int hdcs_probe_1x00(struct sd *sd) | ||
422 | { | ||
423 | struct hdcs *hdcs; | ||
424 | u16 sensor; | ||
425 | int ret; | ||
426 | |||
427 | ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor); | ||
428 | if (ret < 0 || sensor != 0x08) | ||
429 | return -ENODEV; | ||
430 | |||
431 | info("HDCS-1000/1100 sensor detected"); | ||
432 | |||
433 | sd->gspca_dev.cam.cam_mode = hdcs1x00_mode; | ||
434 | sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1x00_mode); | ||
435 | sd->desc.ctrls = hdcs1x00_ctrl; | ||
436 | sd->desc.nctrls = ARRAY_SIZE(hdcs1x00_ctrl); | ||
437 | |||
438 | hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL); | ||
439 | if (!hdcs) | ||
440 | return -ENOMEM; | ||
441 | |||
442 | hdcs->array.left = 8; | ||
443 | hdcs->array.top = 8; | ||
444 | hdcs->array.width = HDCS_1X00_DEF_WIDTH; | ||
445 | hdcs->array.height = HDCS_1X00_DEF_HEIGHT; | ||
446 | hdcs->array.border = 4; | ||
447 | |||
448 | hdcs->exp.cto = 4; | ||
449 | hdcs->exp.cpo = 2; | ||
450 | hdcs->exp.rs = 186; | ||
451 | hdcs->exp.er = 100; | ||
452 | |||
453 | /* | ||
454 | * Frame rate on HDCS-1000 with STV600 depends on PSMP: | ||
455 | * 4 = doesn't work at all | ||
456 | * 5 = 7.8 fps, | ||
457 | * 6 = 6.9 fps, | ||
458 | * 8 = 6.3 fps, | ||
459 | * 10 = 5.5 fps, | ||
460 | * 15 = 4.4 fps, | ||
461 | * 31 = 2.8 fps | ||
462 | * | ||
463 | * Frame rate on HDCS-1000 with STV602 depends on PSMP: | ||
464 | * 15 = doesn't work at all | ||
465 | * 18 = doesn't work at all | ||
466 | * 19 = 7.3 fps | ||
467 | * 20 = 7.4 fps | ||
468 | * 21 = 7.4 fps | ||
469 | * 22 = 7.4 fps | ||
470 | * 24 = 6.3 fps | ||
471 | * 30 = 5.4 fps | ||
472 | */ | ||
473 | hdcs->psmp = (sd->bridge == BRIDGE_STV602) ? 20 : 5; | ||
474 | |||
475 | sd->sensor_priv = hdcs; | ||
476 | |||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | static int hdcs_probe_1020(struct sd *sd) | ||
481 | { | ||
482 | struct hdcs *hdcs; | ||
483 | u16 sensor; | ||
484 | int ret; | ||
485 | |||
486 | ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor); | ||
487 | if (ret < 0 || sensor != 0x10) | ||
488 | return -ENODEV; | ||
489 | |||
490 | info("HDCS-1020 sensor detected"); | ||
491 | |||
492 | sd->gspca_dev.cam.cam_mode = hdcs1020_mode; | ||
493 | sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1020_mode); | ||
494 | sd->desc.ctrls = hdcs1020_ctrl; | ||
495 | sd->desc.nctrls = ARRAY_SIZE(hdcs1020_ctrl); | ||
496 | |||
497 | hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL); | ||
498 | if (!hdcs) | ||
499 | return -ENOMEM; | ||
500 | |||
501 | /* | ||
502 | * From Andrey's test image: looks like HDCS-1020 upper-left | ||
503 | * visible pixel is at 24,8 (y maybe even smaller?) and lower-right | ||
504 | * visible pixel at 375,299 (x maybe even larger?) | ||
505 | */ | ||
506 | hdcs->array.left = 24; | ||
507 | hdcs->array.top = 4; | ||
508 | hdcs->array.width = HDCS_1020_DEF_WIDTH; | ||
509 | hdcs->array.height = 304; | ||
510 | hdcs->array.border = 4; | ||
511 | |||
512 | hdcs->psmp = 6; | ||
513 | |||
514 | hdcs->exp.cto = 3; | ||
515 | hdcs->exp.cpo = 3; | ||
516 | hdcs->exp.rs = 155; | ||
517 | hdcs->exp.er = 96; | ||
518 | |||
519 | sd->sensor_priv = hdcs; | ||
520 | |||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | static int hdcs_start(struct sd *sd) | ||
525 | { | ||
526 | PDEBUG(D_STREAM, "Starting stream"); | ||
527 | |||
528 | return hdcs_set_state(sd, HDCS_STATE_RUN); | ||
529 | } | ||
530 | |||
531 | static int hdcs_stop(struct sd *sd) | ||
532 | { | ||
533 | PDEBUG(D_STREAM, "Halting stream"); | ||
534 | |||
535 | return hdcs_set_state(sd, HDCS_STATE_SLEEP); | ||
536 | } | ||
537 | |||
538 | static void hdcs_disconnect(struct sd *sd) | ||
539 | { | ||
540 | PDEBUG(D_PROBE, "Disconnecting the sensor"); | ||
541 | kfree(sd->sensor_priv); | ||
542 | } | ||
543 | |||
544 | static int hdcs_init(struct sd *sd) | ||
545 | { | ||
546 | struct hdcs *hdcs = sd->sensor_priv; | ||
547 | int i, err = 0; | ||
548 | |||
549 | /* Set the STV0602AA in STV0600 emulation mode */ | ||
550 | if (sd->bridge == BRIDGE_STV602) | ||
551 | stv06xx_write_bridge(sd, STV_STV0600_EMULATION, 1); | ||
552 | |||
553 | /* Execute the bridge init */ | ||
554 | for (i = 0; i < ARRAY_SIZE(stv_bridge_init) && !err; i++) { | ||
555 | err = stv06xx_write_bridge(sd, stv_bridge_init[i][0], | ||
556 | stv_bridge_init[i][1]); | ||
557 | } | ||
558 | if (err < 0) | ||
559 | return err; | ||
560 | |||
561 | /* sensor soft reset */ | ||
562 | hdcs_reset(sd); | ||
563 | |||
564 | /* Execute the sensor init */ | ||
565 | for (i = 0; i < ARRAY_SIZE(stv_sensor_init) && !err; i++) { | ||
566 | err = stv06xx_write_sensor(sd, stv_sensor_init[i][0], | ||
567 | stv_sensor_init[i][1]); | ||
568 | } | ||
569 | if (err < 0) | ||
570 | return err; | ||
571 | |||
572 | /* Enable continuous frame capture, bit 2: stop when frame complete */ | ||
573 | err = stv06xx_write_sensor(sd, HDCS_REG_CONFIG(sd), BIT(3)); | ||
574 | if (err < 0) | ||
575 | return err; | ||
576 | |||
577 | /* Set PGA sample duration | ||
578 | (was 0x7E for the STV602, but caused slow framerate with HDCS-1020) */ | ||
579 | if (IS_1020(sd)) | ||
580 | err = stv06xx_write_sensor(sd, HDCS_TCTRL, | ||
581 | (HDCS_ADC_START_SIG_DUR << 6) | hdcs->psmp); | ||
582 | else | ||
583 | err = stv06xx_write_sensor(sd, HDCS_TCTRL, | ||
584 | (HDCS_ADC_START_SIG_DUR << 5) | hdcs->psmp); | ||
585 | if (err < 0) | ||
586 | return err; | ||
587 | |||
588 | err = hdcs_set_gains(sd, HDCS_DEFAULT_GAIN); | ||
589 | if (err < 0) | ||
590 | return err; | ||
591 | |||
592 | err = hdcs_set_size(sd, hdcs->array.width, hdcs->array.height); | ||
593 | if (err < 0) | ||
594 | return err; | ||
595 | |||
596 | err = hdcs_set_exposure(&sd->gspca_dev, HDCS_DEFAULT_EXPOSURE); | ||
597 | return err; | ||
598 | } | ||
599 | |||
600 | static int hdcs_dump(struct sd *sd) | ||
601 | { | ||
602 | u16 reg, val; | ||
603 | |||
604 | info("Dumping sensor registers:"); | ||
605 | |||
606 | for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH; reg++) { | ||
607 | stv06xx_read_sensor(sd, reg, &val); | ||
608 | info("reg 0x%02x = 0x%02x", reg, val); | ||
609 | } | ||
610 | return 0; | ||
611 | } | ||
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 00000000000..a14a84a5079 --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h | |||
@@ -0,0 +1,207 @@ | |||
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 48 | ||
128 | #define HDCS_DEFAULT_GAIN 50 | ||
129 | |||
130 | static int hdcs_probe_1x00(struct sd *sd); | ||
131 | static int hdcs_probe_1020(struct sd *sd); | ||
132 | static int hdcs_start(struct sd *sd); | ||
133 | static int hdcs_init(struct sd *sd); | ||
134 | static int hdcs_stop(struct sd *sd); | ||
135 | static int hdcs_dump(struct sd *sd); | ||
136 | static void hdcs_disconnect(struct sd *sd); | ||
137 | |||
138 | static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); | ||
139 | static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val); | ||
140 | static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val); | ||
141 | static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val); | ||
142 | |||
143 | const 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 | /* FIXME (see if we can lower min_packet_size, needs testing, and also | ||
150 | adjusting framerate when the bandwidth gets lower) */ | ||
151 | .min_packet_size = { 847 }, | ||
152 | .max_packet_size = { 847 }, | ||
153 | |||
154 | .init = hdcs_init, | ||
155 | .probe = hdcs_probe_1x00, | ||
156 | .start = hdcs_start, | ||
157 | .stop = hdcs_stop, | ||
158 | .disconnect = hdcs_disconnect, | ||
159 | .dump = hdcs_dump, | ||
160 | }; | ||
161 | |||
162 | const struct stv06xx_sensor stv06xx_sensor_hdcs1020 = { | ||
163 | .name = "HDCS-1020", | ||
164 | .i2c_flush = 0, | ||
165 | .i2c_addr = (0x55 << 1), | ||
166 | .i2c_len = 1, | ||
167 | |||
168 | /* FIXME (see if we can lower min_packet_size, needs testing, and also | ||
169 | adjusting framerate when the bandwidthm gets lower) */ | ||
170 | .min_packet_size = { 847 }, | ||
171 | .max_packet_size = { 847 }, | ||
172 | |||
173 | .init = hdcs_init, | ||
174 | .probe = hdcs_probe_1020, | ||
175 | .start = hdcs_start, | ||
176 | .stop = hdcs_stop, | ||
177 | .dump = hdcs_dump, | ||
178 | }; | ||
179 | |||
180 | static const u16 stv_bridge_init[][2] = { | ||
181 | {STV_ISO_ENABLE, 0}, | ||
182 | {STV_REG23, 0}, | ||
183 | {STV_REG00, 0x1d}, | ||
184 | {STV_REG01, 0xb5}, | ||
185 | {STV_REG02, 0xa8}, | ||
186 | {STV_REG03, 0x95}, | ||
187 | {STV_REG04, 0x07}, | ||
188 | |||
189 | {STV_SCAN_RATE, 0x20}, | ||
190 | {STV_Y_CTRL, 0x01}, | ||
191 | {STV_X_CTRL, 0x0a} | ||
192 | }; | ||
193 | |||
194 | static const u8 stv_sensor_init[][2] = { | ||
195 | /* Clear status (writing 1 will clear the corresponding status bit) */ | ||
196 | {HDCS_STATUS, BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1)}, | ||
197 | /* Disable all interrupts */ | ||
198 | {HDCS_IMASK, 0x00}, | ||
199 | {HDCS_PCTRL, BIT(6) | BIT(5) | BIT(1) | BIT(0)}, | ||
200 | {HDCS_PDRV, 0x00}, | ||
201 | {HDCS_ICTRL, BIT(5)}, | ||
202 | {HDCS_ITMG, BIT(4) | BIT(1)}, | ||
203 | /* ADC output resolution to 10 bits */ | ||
204 | {HDCS_ADCCTRL, 10} | ||
205 | }; | ||
206 | |||
207 | #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 00000000000..75a5b9c2f15 --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c | |||
@@ -0,0 +1,573 @@ | |||
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 | |||
49 | static const struct ctrl pb0100_ctrl[] = { | ||
50 | #define GAIN_IDX 0 | ||
51 | { | ||
52 | { | ||
53 | .id = V4L2_CID_GAIN, | ||
54 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
55 | .name = "Gain", | ||
56 | .minimum = 0, | ||
57 | .maximum = 255, | ||
58 | .step = 1, | ||
59 | .default_value = 128 | ||
60 | }, | ||
61 | .set = pb0100_set_gain, | ||
62 | .get = pb0100_get_gain | ||
63 | }, | ||
64 | #define RED_BALANCE_IDX 1 | ||
65 | { | ||
66 | { | ||
67 | .id = V4L2_CID_RED_BALANCE, | ||
68 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
69 | .name = "Red Balance", | ||
70 | .minimum = -255, | ||
71 | .maximum = 255, | ||
72 | .step = 1, | ||
73 | .default_value = 0 | ||
74 | }, | ||
75 | .set = pb0100_set_red_balance, | ||
76 | .get = pb0100_get_red_balance | ||
77 | }, | ||
78 | #define BLUE_BALANCE_IDX 2 | ||
79 | { | ||
80 | { | ||
81 | .id = V4L2_CID_BLUE_BALANCE, | ||
82 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
83 | .name = "Blue Balance", | ||
84 | .minimum = -255, | ||
85 | .maximum = 255, | ||
86 | .step = 1, | ||
87 | .default_value = 0 | ||
88 | }, | ||
89 | .set = pb0100_set_blue_balance, | ||
90 | .get = pb0100_get_blue_balance | ||
91 | }, | ||
92 | #define EXPOSURE_IDX 3 | ||
93 | { | ||
94 | { | ||
95 | .id = V4L2_CID_EXPOSURE, | ||
96 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
97 | .name = "Exposure", | ||
98 | .minimum = 0, | ||
99 | .maximum = 511, | ||
100 | .step = 1, | ||
101 | .default_value = 12 | ||
102 | }, | ||
103 | .set = pb0100_set_exposure, | ||
104 | .get = pb0100_get_exposure | ||
105 | }, | ||
106 | #define AUTOGAIN_IDX 4 | ||
107 | { | ||
108 | { | ||
109 | .id = V4L2_CID_AUTOGAIN, | ||
110 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
111 | .name = "Automatic Gain and Exposure", | ||
112 | .minimum = 0, | ||
113 | .maximum = 1, | ||
114 | .step = 1, | ||
115 | .default_value = 1 | ||
116 | }, | ||
117 | .set = pb0100_set_autogain, | ||
118 | .get = pb0100_get_autogain | ||
119 | }, | ||
120 | #define AUTOGAIN_TARGET_IDX 5 | ||
121 | { | ||
122 | { | ||
123 | .id = V4L2_CTRL_CLASS_USER + 0x1000, | ||
124 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
125 | .name = "Automatic Gain Target", | ||
126 | .minimum = 0, | ||
127 | .maximum = 255, | ||
128 | .step = 1, | ||
129 | .default_value = 128 | ||
130 | }, | ||
131 | .set = pb0100_set_autogain_target, | ||
132 | .get = pb0100_get_autogain_target | ||
133 | }, | ||
134 | #define NATURAL_IDX 6 | ||
135 | { | ||
136 | { | ||
137 | .id = V4L2_CTRL_CLASS_USER + 0x1001, | ||
138 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
139 | .name = "Natural Light Source", | ||
140 | .minimum = 0, | ||
141 | .maximum = 1, | ||
142 | .step = 1, | ||
143 | .default_value = 1 | ||
144 | }, | ||
145 | .set = pb0100_set_natural, | ||
146 | .get = pb0100_get_natural | ||
147 | } | ||
148 | }; | ||
149 | |||
150 | static struct v4l2_pix_format pb0100_mode[] = { | ||
151 | /* low res / subsample modes disabled as they are only half res horizontal, | ||
152 | halving the vertical resolution does not seem to work */ | ||
153 | { | ||
154 | 320, | ||
155 | 240, | ||
156 | V4L2_PIX_FMT_SGRBG8, | ||
157 | V4L2_FIELD_NONE, | ||
158 | .sizeimage = 320 * 240, | ||
159 | .bytesperline = 320, | ||
160 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
161 | .priv = PB0100_CROP_TO_VGA | ||
162 | }, | ||
163 | { | ||
164 | 352, | ||
165 | 288, | ||
166 | V4L2_PIX_FMT_SGRBG8, | ||
167 | V4L2_FIELD_NONE, | ||
168 | .sizeimage = 352 * 288, | ||
169 | .bytesperline = 352, | ||
170 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
171 | .priv = 0 | ||
172 | } | ||
173 | }; | ||
174 | |||
175 | static int pb0100_probe(struct sd *sd) | ||
176 | { | ||
177 | u16 sensor; | ||
178 | int i, err; | ||
179 | s32 *sensor_settings; | ||
180 | |||
181 | err = stv06xx_read_sensor(sd, PB_IDENT, &sensor); | ||
182 | |||
183 | if (err < 0) | ||
184 | return -ENODEV; | ||
185 | |||
186 | if ((sensor >> 8) == 0x64) { | ||
187 | sensor_settings = kmalloc( | ||
188 | ARRAY_SIZE(pb0100_ctrl) * sizeof(s32), | ||
189 | GFP_KERNEL); | ||
190 | if (!sensor_settings) | ||
191 | return -ENOMEM; | ||
192 | |||
193 | info("Photobit pb0100 sensor detected"); | ||
194 | |||
195 | sd->gspca_dev.cam.cam_mode = pb0100_mode; | ||
196 | sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode); | ||
197 | sd->desc.ctrls = pb0100_ctrl; | ||
198 | sd->desc.nctrls = ARRAY_SIZE(pb0100_ctrl); | ||
199 | for (i = 0; i < sd->desc.nctrls; i++) | ||
200 | sensor_settings[i] = pb0100_ctrl[i].qctrl.default_value; | ||
201 | sd->sensor_priv = sensor_settings; | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | return -ENODEV; | ||
207 | } | ||
208 | |||
209 | static int pb0100_start(struct sd *sd) | ||
210 | { | ||
211 | int err, packet_size, max_packet_size; | ||
212 | struct usb_host_interface *alt; | ||
213 | struct usb_interface *intf; | ||
214 | struct cam *cam = &sd->gspca_dev.cam; | ||
215 | s32 *sensor_settings = sd->sensor_priv; | ||
216 | u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv; | ||
217 | |||
218 | intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); | ||
219 | alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); | ||
220 | if (!alt) | ||
221 | return -ENODEV; | ||
222 | packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); | ||
223 | |||
224 | /* If we don't have enough bandwidth use a lower framerate */ | ||
225 | max_packet_size = sd->sensor->max_packet_size[sd->gspca_dev.curr_mode]; | ||
226 | if (packet_size < max_packet_size) | ||
227 | stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1)); | ||
228 | else | ||
229 | stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(5)|BIT(3)|BIT(1)); | ||
230 | |||
231 | /* Setup sensor window */ | ||
232 | if (mode & PB0100_CROP_TO_VGA) { | ||
233 | stv06xx_write_sensor(sd, PB_RSTART, 30); | ||
234 | stv06xx_write_sensor(sd, PB_CSTART, 20); | ||
235 | stv06xx_write_sensor(sd, PB_RWSIZE, 240 - 1); | ||
236 | stv06xx_write_sensor(sd, PB_CWSIZE, 320 - 1); | ||
237 | } else { | ||
238 | stv06xx_write_sensor(sd, PB_RSTART, 8); | ||
239 | stv06xx_write_sensor(sd, PB_CSTART, 4); | ||
240 | stv06xx_write_sensor(sd, PB_RWSIZE, 288 - 1); | ||
241 | stv06xx_write_sensor(sd, PB_CWSIZE, 352 - 1); | ||
242 | } | ||
243 | |||
244 | if (mode & PB0100_SUBSAMPLE) { | ||
245 | stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); /* Wrong, FIXME */ | ||
246 | stv06xx_write_bridge(sd, STV_X_CTRL, 0x06); | ||
247 | |||
248 | stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10); | ||
249 | } else { | ||
250 | stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01); | ||
251 | stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a); | ||
252 | /* larger -> slower */ | ||
253 | stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20); | ||
254 | } | ||
255 | |||
256 | /* set_gain also sets red and blue balance */ | ||
257 | pb0100_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); | ||
258 | pb0100_set_exposure(&sd->gspca_dev, sensor_settings[EXPOSURE_IDX]); | ||
259 | pb0100_set_autogain_target(&sd->gspca_dev, | ||
260 | sensor_settings[AUTOGAIN_TARGET_IDX]); | ||
261 | pb0100_set_autogain(&sd->gspca_dev, sensor_settings[AUTOGAIN_IDX]); | ||
262 | |||
263 | err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)|BIT(1)); | ||
264 | PDEBUG(D_STREAM, "Started stream, status: %d", err); | ||
265 | |||
266 | return (err < 0) ? err : 0; | ||
267 | } | ||
268 | |||
269 | static int pb0100_stop(struct sd *sd) | ||
270 | { | ||
271 | int err; | ||
272 | |||
273 | err = stv06xx_write_sensor(sd, PB_ABORTFRAME, 1); | ||
274 | |||
275 | if (err < 0) | ||
276 | goto out; | ||
277 | |||
278 | /* Set bit 1 to zero */ | ||
279 | err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)); | ||
280 | |||
281 | PDEBUG(D_STREAM, "Halting stream"); | ||
282 | out: | ||
283 | return (err < 0) ? err : 0; | ||
284 | } | ||
285 | |||
286 | static void pb0100_disconnect(struct sd *sd) | ||
287 | { | ||
288 | sd->sensor = NULL; | ||
289 | kfree(sd->sensor_priv); | ||
290 | } | ||
291 | |||
292 | /* FIXME: Sort the init commands out and put them into tables, | ||
293 | this is only for getting the camera to work */ | ||
294 | /* FIXME: No error handling for now, | ||
295 | add this once the init has been converted to proper tables */ | ||
296 | static int pb0100_init(struct sd *sd) | ||
297 | { | ||
298 | stv06xx_write_bridge(sd, STV_REG00, 1); | ||
299 | stv06xx_write_bridge(sd, STV_SCAN_RATE, 0); | ||
300 | |||
301 | /* Reset sensor */ | ||
302 | stv06xx_write_sensor(sd, PB_RESET, 1); | ||
303 | stv06xx_write_sensor(sd, PB_RESET, 0); | ||
304 | |||
305 | /* Disable chip */ | ||
306 | stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)); | ||
307 | |||
308 | /* Gain stuff...*/ | ||
309 | stv06xx_write_sensor(sd, PB_PREADCTRL, BIT(12)|BIT(10)|BIT(6)); | ||
310 | stv06xx_write_sensor(sd, PB_ADCGLOBALGAIN, 12); | ||
311 | |||
312 | /* Set up auto-exposure */ | ||
313 | /* ADC VREF_HI new setting for a transition | ||
314 | from the Expose1 to the Expose2 setting */ | ||
315 | stv06xx_write_sensor(sd, PB_R28, 12); | ||
316 | /* gain max for autoexposure */ | ||
317 | stv06xx_write_sensor(sd, PB_ADCMAXGAIN, 180); | ||
318 | /* gain min for autoexposure */ | ||
319 | stv06xx_write_sensor(sd, PB_ADCMINGAIN, 12); | ||
320 | /* Maximum frame integration time (programmed into R8) | ||
321 | allowed for auto-exposure routine */ | ||
322 | stv06xx_write_sensor(sd, PB_R54, 3); | ||
323 | /* Minimum frame integration time (programmed into R8) | ||
324 | allowed for auto-exposure routine */ | ||
325 | stv06xx_write_sensor(sd, PB_R55, 0); | ||
326 | stv06xx_write_sensor(sd, PB_UPDATEINT, 1); | ||
327 | /* R15 Expose0 (maximum that auto-exposure may use) */ | ||
328 | stv06xx_write_sensor(sd, PB_R15, 800); | ||
329 | /* R17 Expose2 (minimum that auto-exposure may use) */ | ||
330 | stv06xx_write_sensor(sd, PB_R17, 10); | ||
331 | |||
332 | stv06xx_write_sensor(sd, PB_EXPGAIN, 0); | ||
333 | |||
334 | /* 0x14 */ | ||
335 | stv06xx_write_sensor(sd, PB_VOFFSET, 0); | ||
336 | /* 0x0D */ | ||
337 | stv06xx_write_sensor(sd, PB_ADCGAINH, 11); | ||
338 | /* Set black level (important!) */ | ||
339 | stv06xx_write_sensor(sd, PB_ADCGAINL, 0); | ||
340 | |||
341 | /* ??? */ | ||
342 | stv06xx_write_bridge(sd, STV_REG00, 0x11); | ||
343 | stv06xx_write_bridge(sd, STV_REG03, 0x45); | ||
344 | stv06xx_write_bridge(sd, STV_REG04, 0x07); | ||
345 | |||
346 | /* Scan/timing for the sensor */ | ||
347 | stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1)); | ||
348 | stv06xx_write_sensor(sd, PB_CFILLIN, 14); | ||
349 | stv06xx_write_sensor(sd, PB_VBL, 0); | ||
350 | stv06xx_write_sensor(sd, PB_FINTTIME, 0); | ||
351 | stv06xx_write_sensor(sd, PB_RINTTIME, 123); | ||
352 | |||
353 | stv06xx_write_bridge(sd, STV_REG01, 0xc2); | ||
354 | stv06xx_write_bridge(sd, STV_REG02, 0xb0); | ||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | static int pb0100_dump(struct sd *sd) | ||
359 | { | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val) | ||
364 | { | ||
365 | struct sd *sd = (struct sd *) gspca_dev; | ||
366 | s32 *sensor_settings = sd->sensor_priv; | ||
367 | |||
368 | *val = sensor_settings[GAIN_IDX]; | ||
369 | |||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val) | ||
374 | { | ||
375 | int err; | ||
376 | struct sd *sd = (struct sd *) gspca_dev; | ||
377 | s32 *sensor_settings = sd->sensor_priv; | ||
378 | |||
379 | if (sensor_settings[AUTOGAIN_IDX]) | ||
380 | return -EBUSY; | ||
381 | |||
382 | sensor_settings[GAIN_IDX] = val; | ||
383 | err = stv06xx_write_sensor(sd, PB_G1GAIN, val); | ||
384 | if (!err) | ||
385 | err = stv06xx_write_sensor(sd, PB_G2GAIN, val); | ||
386 | PDEBUG(D_V4L2, "Set green gain to %d, status: %d", val, err); | ||
387 | |||
388 | if (!err) | ||
389 | err = pb0100_set_red_balance(gspca_dev, | ||
390 | sensor_settings[RED_BALANCE_IDX]); | ||
391 | if (!err) | ||
392 | err = pb0100_set_blue_balance(gspca_dev, | ||
393 | sensor_settings[BLUE_BALANCE_IDX]); | ||
394 | |||
395 | return err; | ||
396 | } | ||
397 | |||
398 | static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) | ||
399 | { | ||
400 | struct sd *sd = (struct sd *) gspca_dev; | ||
401 | s32 *sensor_settings = sd->sensor_priv; | ||
402 | |||
403 | *val = sensor_settings[RED_BALANCE_IDX]; | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) | ||
409 | { | ||
410 | int err; | ||
411 | struct sd *sd = (struct sd *) gspca_dev; | ||
412 | s32 *sensor_settings = sd->sensor_priv; | ||
413 | |||
414 | if (sensor_settings[AUTOGAIN_IDX]) | ||
415 | return -EBUSY; | ||
416 | |||
417 | sensor_settings[RED_BALANCE_IDX] = val; | ||
418 | val += sensor_settings[GAIN_IDX]; | ||
419 | if (val < 0) | ||
420 | val = 0; | ||
421 | else if (val > 255) | ||
422 | val = 255; | ||
423 | |||
424 | err = stv06xx_write_sensor(sd, PB_RGAIN, val); | ||
425 | PDEBUG(D_V4L2, "Set red gain to %d, status: %d", val, err); | ||
426 | |||
427 | return err; | ||
428 | } | ||
429 | |||
430 | static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) | ||
431 | { | ||
432 | struct sd *sd = (struct sd *) gspca_dev; | ||
433 | s32 *sensor_settings = sd->sensor_priv; | ||
434 | |||
435 | *val = sensor_settings[BLUE_BALANCE_IDX]; | ||
436 | |||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) | ||
441 | { | ||
442 | int err; | ||
443 | struct sd *sd = (struct sd *) gspca_dev; | ||
444 | s32 *sensor_settings = sd->sensor_priv; | ||
445 | |||
446 | if (sensor_settings[AUTOGAIN_IDX]) | ||
447 | return -EBUSY; | ||
448 | |||
449 | sensor_settings[BLUE_BALANCE_IDX] = val; | ||
450 | val += sensor_settings[GAIN_IDX]; | ||
451 | if (val < 0) | ||
452 | val = 0; | ||
453 | else if (val > 255) | ||
454 | val = 255; | ||
455 | |||
456 | err = stv06xx_write_sensor(sd, PB_BGAIN, val); | ||
457 | PDEBUG(D_V4L2, "Set blue gain to %d, status: %d", val, err); | ||
458 | |||
459 | return err; | ||
460 | } | ||
461 | |||
462 | static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) | ||
463 | { | ||
464 | struct sd *sd = (struct sd *) gspca_dev; | ||
465 | s32 *sensor_settings = sd->sensor_priv; | ||
466 | |||
467 | *val = sensor_settings[EXPOSURE_IDX]; | ||
468 | |||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val) | ||
473 | { | ||
474 | int err; | ||
475 | struct sd *sd = (struct sd *) gspca_dev; | ||
476 | s32 *sensor_settings = sd->sensor_priv; | ||
477 | |||
478 | if (sensor_settings[AUTOGAIN_IDX]) | ||
479 | return -EBUSY; | ||
480 | |||
481 | sensor_settings[EXPOSURE_IDX] = val; | ||
482 | err = stv06xx_write_sensor(sd, PB_RINTTIME, val); | ||
483 | PDEBUG(D_V4L2, "Set exposure to %d, status: %d", val, err); | ||
484 | |||
485 | return err; | ||
486 | } | ||
487 | |||
488 | static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val) | ||
489 | { | ||
490 | struct sd *sd = (struct sd *) gspca_dev; | ||
491 | s32 *sensor_settings = sd->sensor_priv; | ||
492 | |||
493 | *val = sensor_settings[AUTOGAIN_IDX]; | ||
494 | |||
495 | return 0; | ||
496 | } | ||
497 | |||
498 | static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val) | ||
499 | { | ||
500 | int err; | ||
501 | struct sd *sd = (struct sd *) gspca_dev; | ||
502 | s32 *sensor_settings = sd->sensor_priv; | ||
503 | |||
504 | sensor_settings[AUTOGAIN_IDX] = val; | ||
505 | if (sensor_settings[AUTOGAIN_IDX]) { | ||
506 | if (sensor_settings[NATURAL_IDX]) | ||
507 | val = BIT(6)|BIT(4)|BIT(0); | ||
508 | else | ||
509 | val = BIT(4)|BIT(0); | ||
510 | } else | ||
511 | val = 0; | ||
512 | |||
513 | err = stv06xx_write_sensor(sd, PB_EXPGAIN, val); | ||
514 | PDEBUG(D_V4L2, "Set autogain to %d (natural: %d), status: %d", | ||
515 | sensor_settings[AUTOGAIN_IDX], sensor_settings[NATURAL_IDX], | ||
516 | err); | ||
517 | |||
518 | return err; | ||
519 | } | ||
520 | |||
521 | static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val) | ||
522 | { | ||
523 | struct sd *sd = (struct sd *) gspca_dev; | ||
524 | s32 *sensor_settings = sd->sensor_priv; | ||
525 | |||
526 | *val = sensor_settings[AUTOGAIN_TARGET_IDX]; | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val) | ||
532 | { | ||
533 | int err, totalpixels, brightpixels, darkpixels; | ||
534 | struct sd *sd = (struct sd *) gspca_dev; | ||
535 | s32 *sensor_settings = sd->sensor_priv; | ||
536 | |||
537 | sensor_settings[AUTOGAIN_TARGET_IDX] = val; | ||
538 | |||
539 | /* Number of pixels counted by the sensor when subsampling the pixels. | ||
540 | * Slightly larger than the real value to avoid oscillation */ | ||
541 | totalpixels = gspca_dev->width * gspca_dev->height; | ||
542 | totalpixels = totalpixels/(8*8) + totalpixels/(64*64); | ||
543 | |||
544 | brightpixels = (totalpixels * val) >> 8; | ||
545 | darkpixels = totalpixels - brightpixels; | ||
546 | err = stv06xx_write_sensor(sd, PB_R21, brightpixels); | ||
547 | if (!err) | ||
548 | err = stv06xx_write_sensor(sd, PB_R22, darkpixels); | ||
549 | |||
550 | PDEBUG(D_V4L2, "Set autogain target to %d, status: %d", val, err); | ||
551 | |||
552 | return err; | ||
553 | } | ||
554 | |||
555 | static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val) | ||
556 | { | ||
557 | struct sd *sd = (struct sd *) gspca_dev; | ||
558 | s32 *sensor_settings = sd->sensor_priv; | ||
559 | |||
560 | *val = sensor_settings[NATURAL_IDX]; | ||
561 | |||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val) | ||
566 | { | ||
567 | struct sd *sd = (struct sd *) gspca_dev; | ||
568 | s32 *sensor_settings = sd->sensor_priv; | ||
569 | |||
570 | sensor_settings[NATURAL_IDX] = val; | ||
571 | |||
572 | return pb0100_set_autogain(gspca_dev, sensor_settings[AUTOGAIN_IDX]); | ||
573 | } | ||
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 00000000000..757de246dc7 --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h | |||
@@ -0,0 +1,152 @@ | |||
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 | |||
112 | static int pb0100_probe(struct sd *sd); | ||
113 | static int pb0100_start(struct sd *sd); | ||
114 | static int pb0100_init(struct sd *sd); | ||
115 | static int pb0100_stop(struct sd *sd); | ||
116 | static int pb0100_dump(struct sd *sd); | ||
117 | static void pb0100_disconnect(struct sd *sd); | ||
118 | |||
119 | /* V4L2 controls supported by the driver */ | ||
120 | static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val); | ||
121 | static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val); | ||
122 | static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); | ||
123 | static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); | ||
124 | static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); | ||
125 | static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); | ||
126 | static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); | ||
127 | static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val); | ||
128 | static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val); | ||
129 | static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val); | ||
130 | static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val); | ||
131 | static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val); | ||
132 | static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val); | ||
133 | static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val); | ||
134 | |||
135 | const struct stv06xx_sensor stv06xx_sensor_pb0100 = { | ||
136 | .name = "PB-0100", | ||
137 | .i2c_flush = 1, | ||
138 | .i2c_addr = 0xba, | ||
139 | .i2c_len = 2, | ||
140 | |||
141 | .min_packet_size = { 635, 847 }, | ||
142 | .max_packet_size = { 847, 923 }, | ||
143 | |||
144 | .init = pb0100_init, | ||
145 | .probe = pb0100_probe, | ||
146 | .start = pb0100_start, | ||
147 | .stop = pb0100_stop, | ||
148 | .dump = pb0100_dump, | ||
149 | .disconnect = pb0100_disconnect, | ||
150 | }; | ||
151 | |||
152 | #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 00000000000..fb229d8ded5 --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h | |||
@@ -0,0 +1,87 @@ | |||
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_1020(sd) ((sd)->sensor == &stv06xx_sensor_hdcs1020) | ||
36 | |||
37 | extern const struct stv06xx_sensor stv06xx_sensor_vv6410; | ||
38 | extern const struct stv06xx_sensor stv06xx_sensor_hdcs1x00; | ||
39 | extern const struct stv06xx_sensor stv06xx_sensor_hdcs1020; | ||
40 | extern const struct stv06xx_sensor stv06xx_sensor_pb0100; | ||
41 | extern const struct stv06xx_sensor stv06xx_sensor_st6422; | ||
42 | |||
43 | struct stv06xx_sensor { | ||
44 | /* Defines the name of a sensor */ | ||
45 | char name[32]; | ||
46 | |||
47 | /* Sensor i2c address */ | ||
48 | u8 i2c_addr; | ||
49 | |||
50 | /* Flush value*/ | ||
51 | u8 i2c_flush; | ||
52 | |||
53 | /* length of an i2c word */ | ||
54 | u8 i2c_len; | ||
55 | |||
56 | /* Isoc packet size (per mode) */ | ||
57 | int min_packet_size[4]; | ||
58 | int max_packet_size[4]; | ||
59 | |||
60 | /* Probes if the sensor is connected */ | ||
61 | int (*probe)(struct sd *sd); | ||
62 | |||
63 | /* Performs a initialization sequence */ | ||
64 | int (*init)(struct sd *sd); | ||
65 | |||
66 | /* Executed at device disconnect */ | ||
67 | void (*disconnect)(struct sd *sd); | ||
68 | |||
69 | /* Reads a sensor register */ | ||
70 | int (*read_sensor)(struct sd *sd, const u8 address, | ||
71 | u8 *i2c_data, const u8 len); | ||
72 | |||
73 | /* Writes to a sensor register */ | ||
74 | int (*write_sensor)(struct sd *sd, const u8 address, | ||
75 | u8 *i2c_data, const u8 len); | ||
76 | |||
77 | /* Instructs the sensor to start streaming */ | ||
78 | int (*start)(struct sd *sd); | ||
79 | |||
80 | /* Instructs the sensor to stop streaming */ | ||
81 | int (*stop)(struct sd *sd); | ||
82 | |||
83 | /* Instructs the sensor to dump all its contents */ | ||
84 | int (*dump)(struct sd *sd); | ||
85 | }; | ||
86 | |||
87 | #endif | ||
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c new file mode 100644 index 00000000000..8a456de4970 --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c | |||
@@ -0,0 +1,401 @@ | |||
1 | /* | ||
2 | * Support for the sensor part which is integrated (I think) into the | ||
3 | * st6422 stv06xx alike bridge, as its integrated there are no i2c writes | ||
4 | * but instead direct bridge writes. | ||
5 | * | ||
6 | * Copyright (c) 2009 Hans de Goede <hdegoede@redhat.com> | ||
7 | * | ||
8 | * Strongly based on qc-usb-messenger, which is: | ||
9 | * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher | ||
10 | * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland | ||
11 | * Copyright (c) 2002, 2003 Tuukka Toivonen | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | #include "stv06xx_st6422.h" | ||
30 | |||
31 | /* controls */ | ||
32 | enum e_ctrl { | ||
33 | BRIGHTNESS, | ||
34 | CONTRAST, | ||
35 | GAIN, | ||
36 | EXPOSURE, | ||
37 | NCTRLS /* number of controls */ | ||
38 | }; | ||
39 | |||
40 | /* sensor settings */ | ||
41 | struct st6422_settings { | ||
42 | struct gspca_ctrl ctrls[NCTRLS]; | ||
43 | }; | ||
44 | |||
45 | static struct v4l2_pix_format st6422_mode[] = { | ||
46 | /* Note we actually get 124 lines of data, of which we skip the 4st | ||
47 | 4 as they are garbage */ | ||
48 | { | ||
49 | 162, | ||
50 | 120, | ||
51 | V4L2_PIX_FMT_SGRBG8, | ||
52 | V4L2_FIELD_NONE, | ||
53 | .sizeimage = 162 * 120, | ||
54 | .bytesperline = 162, | ||
55 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
56 | .priv = 1 | ||
57 | }, | ||
58 | /* Note we actually get 248 lines of data, of which we skip the 4st | ||
59 | 4 as they are garbage, and we tell the app it only gets the | ||
60 | first 240 of the 244 lines it actually gets, so that it ignores | ||
61 | the last 4. */ | ||
62 | { | ||
63 | 324, | ||
64 | 240, | ||
65 | V4L2_PIX_FMT_SGRBG8, | ||
66 | V4L2_FIELD_NONE, | ||
67 | .sizeimage = 324 * 244, | ||
68 | .bytesperline = 324, | ||
69 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
70 | .priv = 0 | ||
71 | }, | ||
72 | }; | ||
73 | |||
74 | /* V4L2 controls supported by the driver */ | ||
75 | static void st6422_set_brightness(struct gspca_dev *gspca_dev); | ||
76 | static void st6422_set_contrast(struct gspca_dev *gspca_dev); | ||
77 | static void st6422_set_gain(struct gspca_dev *gspca_dev); | ||
78 | static void st6422_set_exposure(struct gspca_dev *gspca_dev); | ||
79 | |||
80 | static const struct ctrl st6422_ctrl[NCTRLS] = { | ||
81 | [BRIGHTNESS] = { | ||
82 | { | ||
83 | .id = V4L2_CID_BRIGHTNESS, | ||
84 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
85 | .name = "Brightness", | ||
86 | .minimum = 0, | ||
87 | .maximum = 31, | ||
88 | .step = 1, | ||
89 | .default_value = 3 | ||
90 | }, | ||
91 | .set_control = st6422_set_brightness | ||
92 | }, | ||
93 | [CONTRAST] = { | ||
94 | { | ||
95 | .id = V4L2_CID_CONTRAST, | ||
96 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
97 | .name = "Contrast", | ||
98 | .minimum = 0, | ||
99 | .maximum = 15, | ||
100 | .step = 1, | ||
101 | .default_value = 11 | ||
102 | }, | ||
103 | .set_control = st6422_set_contrast | ||
104 | }, | ||
105 | [GAIN] = { | ||
106 | { | ||
107 | .id = V4L2_CID_GAIN, | ||
108 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
109 | .name = "Gain", | ||
110 | .minimum = 0, | ||
111 | .maximum = 255, | ||
112 | .step = 1, | ||
113 | .default_value = 64 | ||
114 | }, | ||
115 | .set_control = st6422_set_gain | ||
116 | }, | ||
117 | [EXPOSURE] = { | ||
118 | { | ||
119 | .id = V4L2_CID_EXPOSURE, | ||
120 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
121 | .name = "Exposure", | ||
122 | .minimum = 0, | ||
123 | #define EXPOSURE_MAX 1023 | ||
124 | .maximum = EXPOSURE_MAX, | ||
125 | .step = 1, | ||
126 | .default_value = 256 | ||
127 | }, | ||
128 | .set_control = st6422_set_exposure | ||
129 | }, | ||
130 | }; | ||
131 | |||
132 | static int st6422_probe(struct sd *sd) | ||
133 | { | ||
134 | struct st6422_settings *sensor_settings; | ||
135 | |||
136 | if (sd->bridge != BRIDGE_ST6422) | ||
137 | return -ENODEV; | ||
138 | |||
139 | info("st6422 sensor detected"); | ||
140 | |||
141 | sensor_settings = kmalloc(sizeof *sensor_settings, GFP_KERNEL); | ||
142 | if (!sensor_settings) | ||
143 | return -ENOMEM; | ||
144 | |||
145 | sd->gspca_dev.cam.cam_mode = st6422_mode; | ||
146 | sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode); | ||
147 | sd->gspca_dev.cam.ctrls = sensor_settings->ctrls; | ||
148 | sd->desc.ctrls = st6422_ctrl; | ||
149 | sd->desc.nctrls = ARRAY_SIZE(st6422_ctrl); | ||
150 | sd->sensor_priv = sensor_settings; | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static int st6422_init(struct sd *sd) | ||
156 | { | ||
157 | int err = 0, i; | ||
158 | |||
159 | const u16 st6422_bridge_init[][2] = { | ||
160 | { STV_ISO_ENABLE, 0x00 }, /* disable capture */ | ||
161 | { 0x1436, 0x00 }, | ||
162 | { 0x1432, 0x03 }, /* 0x00-0x1F brightness */ | ||
163 | { 0x143a, 0xf9 }, /* 0x00-0x0F contrast */ | ||
164 | { 0x0509, 0x38 }, /* R */ | ||
165 | { 0x050a, 0x38 }, /* G */ | ||
166 | { 0x050b, 0x38 }, /* B */ | ||
167 | { 0x050c, 0x2a }, | ||
168 | { 0x050d, 0x01 }, | ||
169 | |||
170 | |||
171 | { 0x1431, 0x00 }, /* 0x00-0x07 ??? */ | ||
172 | { 0x1433, 0x34 }, /* 160x120, 0x00-0x01 night filter */ | ||
173 | { 0x1438, 0x18 }, /* 640x480 */ | ||
174 | /* 18 bayes */ | ||
175 | /* 10 compressed? */ | ||
176 | |||
177 | { 0x1439, 0x00 }, | ||
178 | /* anti-noise? 0xa2 gives a perfect image */ | ||
179 | |||
180 | { 0x143b, 0x05 }, | ||
181 | { 0x143c, 0x00 }, /* 0x00-0x01 - ??? */ | ||
182 | |||
183 | |||
184 | /* shutter time 0x0000-0x03FF */ | ||
185 | /* low value give good picures on moving objects (but requires much light) */ | ||
186 | /* high value gives good picures in darkness (but tends to be overexposed) */ | ||
187 | { 0x143e, 0x01 }, | ||
188 | { 0x143d, 0x00 }, | ||
189 | |||
190 | { 0x1442, 0xe2 }, | ||
191 | /* write: 1x1x xxxx */ | ||
192 | /* read: 1x1x xxxx */ | ||
193 | /* bit 5 == button pressed and hold if 0 */ | ||
194 | /* write 0xe2,0xea */ | ||
195 | |||
196 | /* 0x144a */ | ||
197 | /* 0x00 init */ | ||
198 | /* bit 7 == button has been pressed, but not handled */ | ||
199 | |||
200 | /* interrupt */ | ||
201 | /* if(urb->iso_frame_desc[i].status == 0x80) { */ | ||
202 | /* if(urb->iso_frame_desc[i].status == 0x88) { */ | ||
203 | |||
204 | { 0x1500, 0xd0 }, | ||
205 | { 0x1500, 0xd0 }, | ||
206 | { 0x1500, 0x50 }, /* 0x00 - 0xFF 0x80 == compr ? */ | ||
207 | |||
208 | { 0x1501, 0xaf }, | ||
209 | /* high val-> light area gets darker */ | ||
210 | /* low val -> light area gets lighter */ | ||
211 | { 0x1502, 0xc2 }, | ||
212 | /* high val-> light area gets darker */ | ||
213 | /* low val -> light area gets lighter */ | ||
214 | { 0x1503, 0x45 }, | ||
215 | /* high val-> light area gets darker */ | ||
216 | /* low val -> light area gets lighter */ | ||
217 | { 0x1505, 0x02 }, | ||
218 | /* 2 : 324x248 80352 bytes */ | ||
219 | /* 7 : 248x162 40176 bytes */ | ||
220 | /* c+f: 162*124 20088 bytes */ | ||
221 | |||
222 | { 0x150e, 0x8e }, | ||
223 | { 0x150f, 0x37 }, | ||
224 | { 0x15c0, 0x00 }, | ||
225 | { 0x15c3, 0x08 }, /* 0x04/0x14 ... test pictures ??? */ | ||
226 | |||
227 | |||
228 | { 0x143f, 0x01 }, /* commit settings */ | ||
229 | |||
230 | }; | ||
231 | |||
232 | for (i = 0; i < ARRAY_SIZE(st6422_bridge_init) && !err; i++) { | ||
233 | err = stv06xx_write_bridge(sd, st6422_bridge_init[i][0], | ||
234 | st6422_bridge_init[i][1]); | ||
235 | } | ||
236 | |||
237 | return err; | ||
238 | } | ||
239 | |||
240 | static void st6422_disconnect(struct sd *sd) | ||
241 | { | ||
242 | sd->sensor = NULL; | ||
243 | kfree(sd->sensor_priv); | ||
244 | } | ||
245 | |||
246 | static int setbrightness(struct sd *sd) | ||
247 | { | ||
248 | struct st6422_settings *sensor_settings = sd->sensor_priv; | ||
249 | |||
250 | /* val goes from 0 -> 31 */ | ||
251 | return stv06xx_write_bridge(sd, 0x1432, | ||
252 | sensor_settings->ctrls[BRIGHTNESS].val); | ||
253 | } | ||
254 | |||
255 | static int setcontrast(struct sd *sd) | ||
256 | { | ||
257 | struct st6422_settings *sensor_settings = sd->sensor_priv; | ||
258 | |||
259 | /* Val goes from 0 -> 15 */ | ||
260 | return stv06xx_write_bridge(sd, 0x143a, | ||
261 | sensor_settings->ctrls[CONTRAST].val | 0xf0); | ||
262 | } | ||
263 | |||
264 | static int setgain(struct sd *sd) | ||
265 | { | ||
266 | struct st6422_settings *sensor_settings = sd->sensor_priv; | ||
267 | u8 gain; | ||
268 | int err; | ||
269 | |||
270 | gain = sensor_settings->ctrls[GAIN].val; | ||
271 | |||
272 | /* Set red, green, blue, gain */ | ||
273 | err = stv06xx_write_bridge(sd, 0x0509, gain); | ||
274 | if (err < 0) | ||
275 | return err; | ||
276 | |||
277 | err = stv06xx_write_bridge(sd, 0x050a, gain); | ||
278 | if (err < 0) | ||
279 | return err; | ||
280 | |||
281 | err = stv06xx_write_bridge(sd, 0x050b, gain); | ||
282 | if (err < 0) | ||
283 | return err; | ||
284 | |||
285 | /* 2 mystery writes */ | ||
286 | err = stv06xx_write_bridge(sd, 0x050c, 0x2a); | ||
287 | if (err < 0) | ||
288 | return err; | ||
289 | |||
290 | return stv06xx_write_bridge(sd, 0x050d, 0x01); | ||
291 | } | ||
292 | |||
293 | static int setexposure(struct sd *sd) | ||
294 | { | ||
295 | struct st6422_settings *sensor_settings = sd->sensor_priv; | ||
296 | u16 expo; | ||
297 | int err; | ||
298 | |||
299 | expo = sensor_settings->ctrls[EXPOSURE].val; | ||
300 | err = stv06xx_write_bridge(sd, 0x143d, expo & 0xff); | ||
301 | if (err < 0) | ||
302 | return err; | ||
303 | |||
304 | return stv06xx_write_bridge(sd, 0x143e, expo >> 8); | ||
305 | } | ||
306 | |||
307 | static int st6422_start(struct sd *sd) | ||
308 | { | ||
309 | int err; | ||
310 | struct cam *cam = &sd->gspca_dev.cam; | ||
311 | |||
312 | if (cam->cam_mode[sd->gspca_dev.curr_mode].priv) | ||
313 | err = stv06xx_write_bridge(sd, 0x1505, 0x0f); | ||
314 | else | ||
315 | err = stv06xx_write_bridge(sd, 0x1505, 0x02); | ||
316 | if (err < 0) | ||
317 | return err; | ||
318 | |||
319 | err = setbrightness(sd); | ||
320 | if (err < 0) | ||
321 | return err; | ||
322 | |||
323 | err = setcontrast(sd); | ||
324 | if (err < 0) | ||
325 | return err; | ||
326 | |||
327 | err = setexposure(sd); | ||
328 | if (err < 0) | ||
329 | return err; | ||
330 | |||
331 | err = setgain(sd); | ||
332 | if (err < 0) | ||
333 | return err; | ||
334 | |||
335 | /* commit settings */ | ||
336 | err = stv06xx_write_bridge(sd, 0x143f, 0x01); | ||
337 | return (err < 0) ? err : 0; | ||
338 | } | ||
339 | |||
340 | static int st6422_stop(struct sd *sd) | ||
341 | { | ||
342 | PDEBUG(D_STREAM, "Halting stream"); | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static void st6422_set_brightness(struct gspca_dev *gspca_dev) | ||
348 | { | ||
349 | int err; | ||
350 | struct sd *sd = (struct sd *) gspca_dev; | ||
351 | |||
352 | err = setbrightness(sd); | ||
353 | |||
354 | /* commit settings */ | ||
355 | if (err >= 0) | ||
356 | err = stv06xx_write_bridge(sd, 0x143f, 0x01); | ||
357 | |||
358 | gspca_dev->usb_err = err; | ||
359 | } | ||
360 | |||
361 | static void st6422_set_contrast(struct gspca_dev *gspca_dev) | ||
362 | { | ||
363 | int err; | ||
364 | struct sd *sd = (struct sd *) gspca_dev; | ||
365 | |||
366 | err = setcontrast(sd); | ||
367 | |||
368 | /* commit settings */ | ||
369 | if (err >= 0) | ||
370 | err = stv06xx_write_bridge(sd, 0x143f, 0x01); | ||
371 | |||
372 | gspca_dev->usb_err = err; | ||
373 | } | ||
374 | |||
375 | static void st6422_set_gain(struct gspca_dev *gspca_dev) | ||
376 | { | ||
377 | int err; | ||
378 | struct sd *sd = (struct sd *) gspca_dev; | ||
379 | |||
380 | err = setgain(sd); | ||
381 | |||
382 | /* commit settings */ | ||
383 | if (err >= 0) | ||
384 | err = stv06xx_write_bridge(sd, 0x143f, 0x01); | ||
385 | |||
386 | gspca_dev->usb_err = err; | ||
387 | } | ||
388 | |||
389 | static void st6422_set_exposure(struct gspca_dev *gspca_dev) | ||
390 | { | ||
391 | int err; | ||
392 | struct sd *sd = (struct sd *) gspca_dev; | ||
393 | |||
394 | err = setexposure(sd); | ||
395 | |||
396 | /* commit settings */ | ||
397 | if (err >= 0) | ||
398 | err = stv06xx_write_bridge(sd, 0x143f, 0x01); | ||
399 | |||
400 | gspca_dev->usb_err = err; | ||
401 | } | ||
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h new file mode 100644 index 00000000000..d7498e06432 --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * Support for the sensor part which is integrated (I think) into the | ||
3 | * st6422 stv06xx alike bridge, as its integrated there are no i2c writes | ||
4 | * but instead direct bridge writes. | ||
5 | * | ||
6 | * Copyright (c) 2009 Hans de Goede <hdegoede@redhat.com> | ||
7 | * | ||
8 | * Strongly based on qc-usb-messenger, which is: | ||
9 | * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher | ||
10 | * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland | ||
11 | * Copyright (c) 2002, 2003 Tuukka Toivonen | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | #ifndef STV06XX_ST6422_H_ | ||
30 | #define STV06XX_ST6422_H_ | ||
31 | |||
32 | #include "stv06xx_sensor.h" | ||
33 | |||
34 | static int st6422_probe(struct sd *sd); | ||
35 | static int st6422_start(struct sd *sd); | ||
36 | static int st6422_init(struct sd *sd); | ||
37 | static int st6422_stop(struct sd *sd); | ||
38 | static void st6422_disconnect(struct sd *sd); | ||
39 | |||
40 | const struct stv06xx_sensor stv06xx_sensor_st6422 = { | ||
41 | .name = "ST6422", | ||
42 | /* No known way to lower framerate in case of less bandwidth */ | ||
43 | .min_packet_size = { 300, 847 }, | ||
44 | .max_packet_size = { 300, 847 }, | ||
45 | .init = st6422_init, | ||
46 | .probe = st6422_probe, | ||
47 | .start = st6422_start, | ||
48 | .stop = st6422_stop, | ||
49 | .disconnect = st6422_disconnect, | ||
50 | }; | ||
51 | |||
52 | #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 00000000000..f8398434c32 --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c | |||
@@ -0,0 +1,392 @@ | |||
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 | |||
32 | static struct v4l2_pix_format vv6410_mode[] = { | ||
33 | { | ||
34 | 356, | ||
35 | 292, | ||
36 | V4L2_PIX_FMT_SGRBG8, | ||
37 | V4L2_FIELD_NONE, | ||
38 | .sizeimage = 356 * 292, | ||
39 | .bytesperline = 356, | ||
40 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
41 | .priv = 0 | ||
42 | } | ||
43 | }; | ||
44 | |||
45 | static const struct ctrl vv6410_ctrl[] = { | ||
46 | #define HFLIP_IDX 0 | ||
47 | { | ||
48 | { | ||
49 | .id = V4L2_CID_HFLIP, | ||
50 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
51 | .name = "horizontal flip", | ||
52 | .minimum = 0, | ||
53 | .maximum = 1, | ||
54 | .step = 1, | ||
55 | .default_value = 0 | ||
56 | }, | ||
57 | .set = vv6410_set_hflip, | ||
58 | .get = vv6410_get_hflip | ||
59 | }, | ||
60 | #define VFLIP_IDX 1 | ||
61 | { | ||
62 | { | ||
63 | .id = V4L2_CID_VFLIP, | ||
64 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
65 | .name = "vertical flip", | ||
66 | .minimum = 0, | ||
67 | .maximum = 1, | ||
68 | .step = 1, | ||
69 | .default_value = 0 | ||
70 | }, | ||
71 | .set = vv6410_set_vflip, | ||
72 | .get = vv6410_get_vflip | ||
73 | }, | ||
74 | #define GAIN_IDX 2 | ||
75 | { | ||
76 | { | ||
77 | .id = V4L2_CID_GAIN, | ||
78 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
79 | .name = "analog gain", | ||
80 | .minimum = 0, | ||
81 | .maximum = 15, | ||
82 | .step = 1, | ||
83 | .default_value = 10 | ||
84 | }, | ||
85 | .set = vv6410_set_analog_gain, | ||
86 | .get = vv6410_get_analog_gain | ||
87 | }, | ||
88 | #define EXPOSURE_IDX 3 | ||
89 | { | ||
90 | { | ||
91 | .id = V4L2_CID_EXPOSURE, | ||
92 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
93 | .name = "exposure", | ||
94 | .minimum = 0, | ||
95 | .maximum = 32768, | ||
96 | .step = 1, | ||
97 | .default_value = 20000 | ||
98 | }, | ||
99 | .set = vv6410_set_exposure, | ||
100 | .get = vv6410_get_exposure | ||
101 | } | ||
102 | }; | ||
103 | |||
104 | static int vv6410_probe(struct sd *sd) | ||
105 | { | ||
106 | u16 data; | ||
107 | int err, i; | ||
108 | s32 *sensor_settings; | ||
109 | |||
110 | err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data); | ||
111 | if (err < 0) | ||
112 | return -ENODEV; | ||
113 | |||
114 | if (data == 0x19) { | ||
115 | info("vv6410 sensor detected"); | ||
116 | |||
117 | sensor_settings = kmalloc(ARRAY_SIZE(vv6410_ctrl) * sizeof(s32), | ||
118 | GFP_KERNEL); | ||
119 | if (!sensor_settings) | ||
120 | return -ENOMEM; | ||
121 | |||
122 | sd->gspca_dev.cam.cam_mode = vv6410_mode; | ||
123 | sd->gspca_dev.cam.nmodes = ARRAY_SIZE(vv6410_mode); | ||
124 | sd->desc.ctrls = vv6410_ctrl; | ||
125 | sd->desc.nctrls = ARRAY_SIZE(vv6410_ctrl); | ||
126 | |||
127 | for (i = 0; i < sd->desc.nctrls; i++) | ||
128 | sensor_settings[i] = vv6410_ctrl[i].qctrl.default_value; | ||
129 | sd->sensor_priv = sensor_settings; | ||
130 | return 0; | ||
131 | } | ||
132 | return -ENODEV; | ||
133 | } | ||
134 | |||
135 | static int vv6410_init(struct sd *sd) | ||
136 | { | ||
137 | int err = 0, i; | ||
138 | s32 *sensor_settings = sd->sensor_priv; | ||
139 | |||
140 | for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) { | ||
141 | /* if NULL then len contains single value */ | ||
142 | if (stv_bridge_init[i].data == NULL) { | ||
143 | err = stv06xx_write_bridge(sd, | ||
144 | stv_bridge_init[i].start, | ||
145 | stv_bridge_init[i].len); | ||
146 | } else { | ||
147 | int j; | ||
148 | for (j = 0; j < stv_bridge_init[i].len; j++) | ||
149 | err = stv06xx_write_bridge(sd, | ||
150 | stv_bridge_init[i].start + j, | ||
151 | stv_bridge_init[i].data[j]); | ||
152 | } | ||
153 | } | ||
154 | |||
155 | if (err < 0) | ||
156 | return err; | ||
157 | |||
158 | err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init, | ||
159 | ARRAY_SIZE(vv6410_sensor_init)); | ||
160 | if (err < 0) | ||
161 | return err; | ||
162 | |||
163 | err = vv6410_set_exposure(&sd->gspca_dev, | ||
164 | sensor_settings[EXPOSURE_IDX]); | ||
165 | if (err < 0) | ||
166 | return err; | ||
167 | |||
168 | err = vv6410_set_analog_gain(&sd->gspca_dev, | ||
169 | sensor_settings[GAIN_IDX]); | ||
170 | |||
171 | return (err < 0) ? err : 0; | ||
172 | } | ||
173 | |||
174 | static void vv6410_disconnect(struct sd *sd) | ||
175 | { | ||
176 | sd->sensor = NULL; | ||
177 | kfree(sd->sensor_priv); | ||
178 | } | ||
179 | |||
180 | static int vv6410_start(struct sd *sd) | ||
181 | { | ||
182 | int err; | ||
183 | struct cam *cam = &sd->gspca_dev.cam; | ||
184 | u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv; | ||
185 | |||
186 | if (priv & VV6410_CROP_TO_QVGA) { | ||
187 | PDEBUG(D_CONF, "Cropping to QVGA"); | ||
188 | stv06xx_write_sensor(sd, VV6410_XENDH, 320 - 1); | ||
189 | stv06xx_write_sensor(sd, VV6410_YENDH, 240 - 1); | ||
190 | } else { | ||
191 | stv06xx_write_sensor(sd, VV6410_XENDH, 360 - 1); | ||
192 | stv06xx_write_sensor(sd, VV6410_YENDH, 294 - 1); | ||
193 | } | ||
194 | |||
195 | if (priv & VV6410_SUBSAMPLE) { | ||
196 | PDEBUG(D_CONF, "Enabling subsampling"); | ||
197 | stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); | ||
198 | stv06xx_write_bridge(sd, STV_X_CTRL, 0x06); | ||
199 | |||
200 | stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10); | ||
201 | } else { | ||
202 | stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01); | ||
203 | stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a); | ||
204 | |||
205 | stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20); | ||
206 | } | ||
207 | |||
208 | /* Turn on LED */ | ||
209 | err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_ON); | ||
210 | if (err < 0) | ||
211 | return err; | ||
212 | |||
213 | err = stv06xx_write_sensor(sd, VV6410_SETUP0, 0); | ||
214 | if (err < 0) | ||
215 | return err; | ||
216 | |||
217 | PDEBUG(D_STREAM, "Starting stream"); | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static int vv6410_stop(struct sd *sd) | ||
223 | { | ||
224 | int err; | ||
225 | |||
226 | /* Turn off LED */ | ||
227 | err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_OFF); | ||
228 | if (err < 0) | ||
229 | return err; | ||
230 | |||
231 | err = stv06xx_write_sensor(sd, VV6410_SETUP0, VV6410_LOW_POWER_MODE); | ||
232 | if (err < 0) | ||
233 | return err; | ||
234 | |||
235 | PDEBUG(D_STREAM, "Halting stream"); | ||
236 | |||
237 | return (err < 0) ? err : 0; | ||
238 | } | ||
239 | |||
240 | static int vv6410_dump(struct sd *sd) | ||
241 | { | ||
242 | u8 i; | ||
243 | int err = 0; | ||
244 | |||
245 | info("Dumping all vv6410 sensor registers"); | ||
246 | for (i = 0; i < 0xff && !err; i++) { | ||
247 | u16 data; | ||
248 | err = stv06xx_read_sensor(sd, i, &data); | ||
249 | info("Register 0x%x contained 0x%x", i, data); | ||
250 | } | ||
251 | return (err < 0) ? err : 0; | ||
252 | } | ||
253 | |||
254 | static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) | ||
255 | { | ||
256 | struct sd *sd = (struct sd *) gspca_dev; | ||
257 | s32 *sensor_settings = sd->sensor_priv; | ||
258 | |||
259 | *val = sensor_settings[HFLIP_IDX]; | ||
260 | PDEBUG(D_V4L2, "Read horizontal flip %d", *val); | ||
261 | |||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val) | ||
266 | { | ||
267 | int err; | ||
268 | u16 i2c_data; | ||
269 | struct sd *sd = (struct sd *) gspca_dev; | ||
270 | s32 *sensor_settings = sd->sensor_priv; | ||
271 | |||
272 | sensor_settings[HFLIP_IDX] = val; | ||
273 | err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); | ||
274 | if (err < 0) | ||
275 | return err; | ||
276 | |||
277 | if (val) | ||
278 | i2c_data |= VV6410_HFLIP; | ||
279 | else | ||
280 | i2c_data &= ~VV6410_HFLIP; | ||
281 | |||
282 | PDEBUG(D_V4L2, "Set horizontal flip to %d", val); | ||
283 | err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); | ||
284 | |||
285 | return (err < 0) ? err : 0; | ||
286 | } | ||
287 | |||
288 | static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) | ||
289 | { | ||
290 | struct sd *sd = (struct sd *) gspca_dev; | ||
291 | s32 *sensor_settings = sd->sensor_priv; | ||
292 | |||
293 | *val = sensor_settings[VFLIP_IDX]; | ||
294 | PDEBUG(D_V4L2, "Read vertical flip %d", *val); | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val) | ||
300 | { | ||
301 | int err; | ||
302 | u16 i2c_data; | ||
303 | struct sd *sd = (struct sd *) gspca_dev; | ||
304 | s32 *sensor_settings = sd->sensor_priv; | ||
305 | |||
306 | sensor_settings[VFLIP_IDX] = val; | ||
307 | err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); | ||
308 | if (err < 0) | ||
309 | return err; | ||
310 | |||
311 | if (val) | ||
312 | i2c_data |= VV6410_VFLIP; | ||
313 | else | ||
314 | i2c_data &= ~VV6410_VFLIP; | ||
315 | |||
316 | PDEBUG(D_V4L2, "Set vertical flip to %d", val); | ||
317 | err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); | ||
318 | |||
319 | return (err < 0) ? err : 0; | ||
320 | } | ||
321 | |||
322 | static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val) | ||
323 | { | ||
324 | struct sd *sd = (struct sd *) gspca_dev; | ||
325 | s32 *sensor_settings = sd->sensor_priv; | ||
326 | |||
327 | *val = sensor_settings[GAIN_IDX]; | ||
328 | |||
329 | PDEBUG(D_V4L2, "Read analog gain %d", *val); | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val) | ||
335 | { | ||
336 | int err; | ||
337 | struct sd *sd = (struct sd *) gspca_dev; | ||
338 | s32 *sensor_settings = sd->sensor_priv; | ||
339 | |||
340 | sensor_settings[GAIN_IDX] = val; | ||
341 | PDEBUG(D_V4L2, "Set analog gain to %d", val); | ||
342 | err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf)); | ||
343 | |||
344 | return (err < 0) ? err : 0; | ||
345 | } | ||
346 | |||
347 | static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) | ||
348 | { | ||
349 | struct sd *sd = (struct sd *) gspca_dev; | ||
350 | s32 *sensor_settings = sd->sensor_priv; | ||
351 | |||
352 | *val = sensor_settings[EXPOSURE_IDX]; | ||
353 | |||
354 | PDEBUG(D_V4L2, "Read exposure %d", *val); | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val) | ||
360 | { | ||
361 | int err; | ||
362 | struct sd *sd = (struct sd *) gspca_dev; | ||
363 | s32 *sensor_settings = sd->sensor_priv; | ||
364 | unsigned int fine, coarse; | ||
365 | |||
366 | sensor_settings[EXPOSURE_IDX] = val; | ||
367 | |||
368 | val = (val * val >> 14) + val / 4; | ||
369 | |||
370 | fine = val % VV6410_CIF_LINELENGTH; | ||
371 | coarse = min(512, val / VV6410_CIF_LINELENGTH); | ||
372 | |||
373 | PDEBUG(D_V4L2, "Set coarse exposure to %d, fine expsure to %d", | ||
374 | coarse, fine); | ||
375 | |||
376 | err = stv06xx_write_sensor(sd, VV6410_FINEH, fine >> 8); | ||
377 | if (err < 0) | ||
378 | goto out; | ||
379 | |||
380 | err = stv06xx_write_sensor(sd, VV6410_FINEL, fine & 0xff); | ||
381 | if (err < 0) | ||
382 | goto out; | ||
383 | |||
384 | err = stv06xx_write_sensor(sd, VV6410_COARSEH, coarse >> 8); | ||
385 | if (err < 0) | ||
386 | goto out; | ||
387 | |||
388 | err = stv06xx_write_sensor(sd, VV6410_COARSEL, coarse & 0xff); | ||
389 | |||
390 | out: | ||
391 | return err; | ||
392 | } | ||
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 00000000000..7fe3587f5f7 --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h | |||
@@ -0,0 +1,259 @@ | |||
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 | |||
176 | #define VV6410_CIF_LINELENGTH 415 | ||
177 | |||
178 | static int vv6410_probe(struct sd *sd); | ||
179 | static int vv6410_start(struct sd *sd); | ||
180 | static int vv6410_init(struct sd *sd); | ||
181 | static int vv6410_stop(struct sd *sd); | ||
182 | static int vv6410_dump(struct sd *sd); | ||
183 | static void vv6410_disconnect(struct sd *sd); | ||
184 | |||
185 | /* V4L2 controls supported by the driver */ | ||
186 | static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); | ||
187 | static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val); | ||
188 | static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); | ||
189 | static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val); | ||
190 | static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val); | ||
191 | static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val); | ||
192 | static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); | ||
193 | static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val); | ||
194 | |||
195 | const struct stv06xx_sensor stv06xx_sensor_vv6410 = { | ||
196 | .name = "ST VV6410", | ||
197 | .i2c_flush = 5, | ||
198 | .i2c_addr = 0x20, | ||
199 | .i2c_len = 1, | ||
200 | /* FIXME (see if we can lower packet_size-s, needs testing, and also | ||
201 | adjusting framerate when the bandwidth gets lower) */ | ||
202 | .min_packet_size = { 1023 }, | ||
203 | .max_packet_size = { 1023 }, | ||
204 | .init = vv6410_init, | ||
205 | .probe = vv6410_probe, | ||
206 | .start = vv6410_start, | ||
207 | .stop = vv6410_stop, | ||
208 | .dump = vv6410_dump, | ||
209 | .disconnect = vv6410_disconnect, | ||
210 | }; | ||
211 | |||
212 | /* If NULL, only single value to write, stored in len */ | ||
213 | struct stv_init { | ||
214 | const u8 *data; | ||
215 | u16 start; | ||
216 | u8 len; | ||
217 | }; | ||
218 | |||
219 | static const u8 x1500[] = { /* 0x1500 - 0x150f */ | ||
220 | 0x0b, 0xa7, 0xb7, 0x00, 0x00 | ||
221 | }; | ||
222 | |||
223 | static const u8 x1536[] = { /* 0x1536 - 0x153b */ | ||
224 | 0x02, 0x00, 0x60, 0x01, 0x20, 0x01 | ||
225 | }; | ||
226 | |||
227 | static const struct stv_init stv_bridge_init[] = { | ||
228 | /* This reg is written twice. Some kind of reset? */ | ||
229 | {NULL, 0x1620, 0x80}, | ||
230 | {NULL, 0x1620, 0x00}, | ||
231 | {NULL, 0x1443, 0x00}, | ||
232 | {NULL, 0x1423, 0x04}, | ||
233 | {x1500, 0x1500, ARRAY_SIZE(x1500)}, | ||
234 | {x1536, 0x1536, ARRAY_SIZE(x1536)}, | ||
235 | }; | ||
236 | |||
237 | static const u8 vv6410_sensor_init[][2] = { | ||
238 | /* Setup registers */ | ||
239 | {VV6410_SETUP0, VV6410_SOFT_RESET}, | ||
240 | {VV6410_SETUP0, VV6410_LOW_POWER_MODE}, | ||
241 | /* Use shuffled read-out mode */ | ||
242 | {VV6410_SETUP1, BIT(6)}, | ||
243 | /* All modes to 1 */ | ||
244 | {VV6410_FGMODES, BIT(6) | BIT(4) | BIT(2) | BIT(0)}, | ||
245 | {VV6410_PINMAPPING, 0x00}, | ||
246 | /* Pre-clock generator divide off */ | ||
247 | {VV6410_DATAFORMAT, BIT(7) | BIT(0)}, | ||
248 | |||
249 | {VV6410_CLKDIV, VV6410_CLK_DIV_2}, | ||
250 | |||
251 | /* System registers */ | ||
252 | /* Enable voltage doubler */ | ||
253 | {VV6410_AS0, BIT(6) | BIT(4) | BIT(3) | BIT(2) | BIT(1)}, | ||
254 | {VV6410_AT0, 0x00}, | ||
255 | /* Power up audio, differential */ | ||
256 | {VV6410_AT1, BIT(4)|BIT(0)}, | ||
257 | }; | ||
258 | |||
259 | #endif | ||