diff options
Diffstat (limited to 'drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c')
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c | 251 |
1 files changed, 251 insertions, 0 deletions
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..1ca91f2a6de --- /dev/null +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c | |||
@@ -0,0 +1,251 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher | ||
3 | * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland | ||
4 | * Copyright (c) 2002, 2003 Tuukka Toivonen | ||
5 | * Copyright (c) 2008 Erik Andrén | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | * | ||
21 | * P/N 861037: Sensor HDCS1000 ASIC STV0600 | ||
22 | * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 | ||
23 | * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express | ||
24 | * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam | ||
25 | * P/N 861075-0040: Sensor HDCS1000 ASIC | ||
26 | * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB | ||
27 | * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web | ||
28 | */ | ||
29 | |||
30 | #include "stv06xx_vv6410.h" | ||
31 | |||
32 | static int vv6410_probe(struct sd *sd) | ||
33 | { | ||
34 | u16 data; | ||
35 | int err; | ||
36 | |||
37 | err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data); | ||
38 | |||
39 | if (err < 0) | ||
40 | return -ENODEV; | ||
41 | |||
42 | if (data == 0x19) { | ||
43 | info("vv6410 sensor detected"); | ||
44 | |||
45 | sd->gspca_dev.cam.cam_mode = stv06xx_sensor_vv6410.modes; | ||
46 | sd->gspca_dev.cam.nmodes = stv06xx_sensor_vv6410.nmodes; | ||
47 | sd->desc.ctrls = stv06xx_sensor_vv6410.ctrls; | ||
48 | sd->desc.nctrls = stv06xx_sensor_vv6410.nctrls; | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | return -ENODEV; | ||
53 | } | ||
54 | |||
55 | static int vv6410_init(struct sd *sd) | ||
56 | { | ||
57 | int err = 0, i; | ||
58 | |||
59 | for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) { | ||
60 | /* if NULL then len contains single value */ | ||
61 | if (stv_bridge_init[i].data == NULL) { | ||
62 | err = stv06xx_write_bridge(sd, | ||
63 | stv_bridge_init[i].start, | ||
64 | stv_bridge_init[i].len); | ||
65 | } else { | ||
66 | int j; | ||
67 | for (j = 0; j < stv_bridge_init[i].len; j++) | ||
68 | err = stv06xx_write_bridge(sd, | ||
69 | stv_bridge_init[i].start + j, | ||
70 | stv_bridge_init[i].data[j]); | ||
71 | } | ||
72 | } | ||
73 | |||
74 | if (err < 0) | ||
75 | return err; | ||
76 | |||
77 | err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init, | ||
78 | ARRAY_SIZE(vv6410_sensor_init)); | ||
79 | |||
80 | return (err < 0) ? err : 0; | ||
81 | } | ||
82 | |||
83 | static int vv6410_start(struct sd *sd) | ||
84 | { | ||
85 | int err; | ||
86 | struct cam *cam = &sd->gspca_dev.cam; | ||
87 | u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv; | ||
88 | |||
89 | if (priv & VV6410_CROP_TO_QVGA) { | ||
90 | PDEBUG(D_CONF, "Cropping to QVGA"); | ||
91 | stv06xx_write_sensor(sd, VV6410_XENDH, 320 - 1); | ||
92 | stv06xx_write_sensor(sd, VV6410_YENDH, 240 - 1); | ||
93 | } else { | ||
94 | stv06xx_write_sensor(sd, VV6410_XENDH, 360 - 1); | ||
95 | stv06xx_write_sensor(sd, VV6410_YENDH, 294 - 1); | ||
96 | } | ||
97 | |||
98 | if (priv & VV6410_SUBSAMPLE) { | ||
99 | PDEBUG(D_CONF, "Enabling subsampling"); | ||
100 | stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); | ||
101 | stv06xx_write_bridge(sd, STV_X_CTRL, 0x06); | ||
102 | |||
103 | stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10); | ||
104 | } else { | ||
105 | stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01); | ||
106 | stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a); | ||
107 | |||
108 | stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20); | ||
109 | } | ||
110 | |||
111 | /* Turn on LED */ | ||
112 | err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_ON); | ||
113 | if (err < 0) | ||
114 | return err; | ||
115 | |||
116 | err = stv06xx_write_sensor(sd, VV6410_SETUP0, 0); | ||
117 | if (err < 0) | ||
118 | return err; | ||
119 | |||
120 | PDEBUG(D_STREAM, "Starting stream"); | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static int vv6410_stop(struct sd *sd) | ||
126 | { | ||
127 | int err; | ||
128 | |||
129 | /* Turn off LED */ | ||
130 | err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_OFF); | ||
131 | if (err < 0) | ||
132 | return err; | ||
133 | |||
134 | err = stv06xx_write_sensor(sd, VV6410_SETUP0, VV6410_LOW_POWER_MODE); | ||
135 | if (err < 0) | ||
136 | return err; | ||
137 | |||
138 | PDEBUG(D_STREAM, "Halting stream"); | ||
139 | |||
140 | return (err < 0) ? err : 0; | ||
141 | } | ||
142 | |||
143 | static int vv6410_dump(struct sd *sd) | ||
144 | { | ||
145 | u8 i; | ||
146 | int err = 0; | ||
147 | |||
148 | info("Dumping all vv6410 sensor registers"); | ||
149 | for (i = 0; i < 0xff && !err; i++) { | ||
150 | u16 data; | ||
151 | err = stv06xx_read_sensor(sd, i, &data); | ||
152 | info("Register 0x%x contained 0x%x", i, data); | ||
153 | } | ||
154 | return (err < 0) ? err : 0; | ||
155 | } | ||
156 | |||
157 | static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) | ||
158 | { | ||
159 | int err; | ||
160 | u16 i2c_data; | ||
161 | struct sd *sd = (struct sd *) gspca_dev; | ||
162 | |||
163 | err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); | ||
164 | |||
165 | *val = (i2c_data & VV6410_HFLIP) ? 1 : 0; | ||
166 | |||
167 | PDEBUG(D_V4L2, "Read horizontal flip %d", *val); | ||
168 | |||
169 | return (err < 0) ? err : 0; | ||
170 | } | ||
171 | |||
172 | static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val) | ||
173 | { | ||
174 | int err; | ||
175 | u16 i2c_data; | ||
176 | struct sd *sd = (struct sd *) gspca_dev; | ||
177 | err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); | ||
178 | if (err < 0) | ||
179 | return err; | ||
180 | |||
181 | if (val) | ||
182 | i2c_data |= VV6410_HFLIP; | ||
183 | else | ||
184 | i2c_data &= ~VV6410_HFLIP; | ||
185 | |||
186 | PDEBUG(D_V4L2, "Set horizontal flip to %d", val); | ||
187 | err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); | ||
188 | |||
189 | return (err < 0) ? err : 0; | ||
190 | } | ||
191 | |||
192 | static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) | ||
193 | { | ||
194 | int err; | ||
195 | u16 i2c_data; | ||
196 | struct sd *sd = (struct sd *) gspca_dev; | ||
197 | |||
198 | err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); | ||
199 | |||
200 | *val = (i2c_data & VV6410_VFLIP) ? 1 : 0; | ||
201 | |||
202 | PDEBUG(D_V4L2, "Read vertical flip %d", *val); | ||
203 | |||
204 | return (err < 0) ? err : 0; | ||
205 | } | ||
206 | |||
207 | static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val) | ||
208 | { | ||
209 | int err; | ||
210 | u16 i2c_data; | ||
211 | struct sd *sd = (struct sd *) gspca_dev; | ||
212 | err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); | ||
213 | if (err < 0) | ||
214 | return err; | ||
215 | |||
216 | if (val) | ||
217 | i2c_data |= VV6410_VFLIP; | ||
218 | else | ||
219 | i2c_data &= ~VV6410_VFLIP; | ||
220 | |||
221 | PDEBUG(D_V4L2, "Set vertical flip to %d", val); | ||
222 | err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); | ||
223 | |||
224 | return (err < 0) ? err : 0; | ||
225 | } | ||
226 | |||
227 | static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val) | ||
228 | { | ||
229 | int err; | ||
230 | u16 i2c_data; | ||
231 | struct sd *sd = (struct sd *) gspca_dev; | ||
232 | |||
233 | err = stv06xx_read_sensor(sd, VV6410_ANALOGGAIN, &i2c_data); | ||
234 | |||
235 | *val = i2c_data & 0xf; | ||
236 | |||
237 | PDEBUG(D_V4L2, "Read analog gain %d", *val); | ||
238 | |||
239 | return (err < 0) ? err : 0; | ||
240 | } | ||
241 | |||
242 | static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val) | ||
243 | { | ||
244 | int err; | ||
245 | struct sd *sd = (struct sd *) gspca_dev; | ||
246 | |||
247 | PDEBUG(D_V4L2, "Set analog gain to %d", val); | ||
248 | err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf)); | ||
249 | |||
250 | return (err < 0) ? err : 0; | ||
251 | } | ||