diff options
Diffstat (limited to 'drivers/media/video/gspca/sq930x.c')
-rw-r--r-- | drivers/media/video/gspca/sq930x.c | 1208 |
1 files changed, 1208 insertions, 0 deletions
diff --git a/drivers/media/video/gspca/sq930x.c b/drivers/media/video/gspca/sq930x.c new file mode 100644 index 00000000000..8215d5dcd45 --- /dev/null +++ b/drivers/media/video/gspca/sq930x.c | |||
@@ -0,0 +1,1208 @@ | |||
1 | /* | ||
2 | * SQ930x subdriver | ||
3 | * | ||
4 | * Copyright (C) 2010 Jean-François Moine <http://moinejf.free.fr> | ||
5 | * Copyright (C) 2006 -2008 Gerard Klaver <gerard at gkall dot hobby dot nl> | ||
6 | * Copyright (C) 2007 Sam Revitch <samr7@cs.washington.edu> | ||
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 | * 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 | |||
23 | #define MODULE_NAME "sq930x" | ||
24 | |||
25 | #include "gspca.h" | ||
26 | |||
27 | MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>\n" | ||
28 | "Gerard Klaver <gerard at gkall dot hobby dot nl\n" | ||
29 | "Sam Revitch <samr7@cs.washington.edu>"); | ||
30 | MODULE_DESCRIPTION("GSPCA/SQ930x USB Camera Driver"); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | /* Structure to hold all of our device specific stuff */ | ||
34 | struct sd { | ||
35 | struct gspca_dev gspca_dev; /* !! must be the first item */ | ||
36 | |||
37 | u16 expo; | ||
38 | u8 gain; | ||
39 | |||
40 | u8 do_ctrl; | ||
41 | u8 gpio[2]; | ||
42 | u8 sensor; | ||
43 | u8 type; | ||
44 | #define Generic 0 | ||
45 | #define Creative_live_motion 1 | ||
46 | }; | ||
47 | enum sensors { | ||
48 | SENSOR_ICX098BQ, | ||
49 | SENSOR_LZ24BP, | ||
50 | SENSOR_MI0360, | ||
51 | SENSOR_MT9V111, /* = MI360SOC */ | ||
52 | SENSOR_OV7660, | ||
53 | SENSOR_OV9630, | ||
54 | }; | ||
55 | |||
56 | static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val); | ||
57 | static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val); | ||
58 | static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); | ||
59 | static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); | ||
60 | |||
61 | static const struct ctrl sd_ctrls[] = { | ||
62 | { | ||
63 | { | ||
64 | .id = V4L2_CID_EXPOSURE, | ||
65 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
66 | .name = "Exposure", | ||
67 | .minimum = 0x0001, | ||
68 | .maximum = 0x0fff, | ||
69 | .step = 1, | ||
70 | #define EXPO_DEF 0x0356 | ||
71 | .default_value = EXPO_DEF, | ||
72 | }, | ||
73 | .set = sd_setexpo, | ||
74 | .get = sd_getexpo, | ||
75 | }, | ||
76 | { | ||
77 | { | ||
78 | .id = V4L2_CID_GAIN, | ||
79 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
80 | .name = "Gain", | ||
81 | .minimum = 0x01, | ||
82 | .maximum = 0xff, | ||
83 | .step = 1, | ||
84 | #define GAIN_DEF 0x8d | ||
85 | .default_value = GAIN_DEF, | ||
86 | }, | ||
87 | .set = sd_setgain, | ||
88 | .get = sd_getgain, | ||
89 | }, | ||
90 | }; | ||
91 | |||
92 | static struct v4l2_pix_format vga_mode[] = { | ||
93 | {320, 240, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE, | ||
94 | .bytesperline = 320, | ||
95 | .sizeimage = 320 * 240, | ||
96 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
97 | .priv = 0}, | ||
98 | {640, 480, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE, | ||
99 | .bytesperline = 640, | ||
100 | .sizeimage = 640 * 480, | ||
101 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
102 | .priv = 1}, | ||
103 | }; | ||
104 | |||
105 | /* sq930x registers */ | ||
106 | #define SQ930_CTRL_UCBUS_IO 0x0001 | ||
107 | #define SQ930_CTRL_I2C_IO 0x0002 | ||
108 | #define SQ930_CTRL_GPIO 0x0005 | ||
109 | #define SQ930_CTRL_CAP_START 0x0010 | ||
110 | #define SQ930_CTRL_CAP_STOP 0x0011 | ||
111 | #define SQ930_CTRL_SET_EXPOSURE 0x001d | ||
112 | #define SQ930_CTRL_RESET 0x001e | ||
113 | #define SQ930_CTRL_GET_DEV_INFO 0x001f | ||
114 | |||
115 | /* gpio 1 (8..15) */ | ||
116 | #define SQ930_GPIO_DFL_I2C_SDA 0x0001 | ||
117 | #define SQ930_GPIO_DFL_I2C_SCL 0x0002 | ||
118 | #define SQ930_GPIO_RSTBAR 0x0004 | ||
119 | #define SQ930_GPIO_EXTRA1 0x0040 | ||
120 | #define SQ930_GPIO_EXTRA2 0x0080 | ||
121 | /* gpio 3 (24..31) */ | ||
122 | #define SQ930_GPIO_POWER 0x0200 | ||
123 | #define SQ930_GPIO_DFL_LED 0x1000 | ||
124 | |||
125 | struct ucbus_write_cmd { | ||
126 | u16 bw_addr; | ||
127 | u8 bw_data; | ||
128 | }; | ||
129 | struct i2c_write_cmd { | ||
130 | u8 reg; | ||
131 | u16 val; | ||
132 | }; | ||
133 | |||
134 | static const struct ucbus_write_cmd icx098bq_start_0[] = { | ||
135 | {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xce}, | ||
136 | {0xf802, 0xc1}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x0e}, | ||
137 | {0xf80a, 0x01}, {0xf80b, 0xee}, {0xf807, 0x60}, {0xf80c, 0x02}, | ||
138 | {0xf80d, 0xf0}, {0xf80e, 0x03}, {0xf80f, 0x0a}, {0xf81c, 0x02}, | ||
139 | {0xf81d, 0xf0}, {0xf81e, 0x03}, {0xf81f, 0x0a}, {0xf83a, 0x00}, | ||
140 | {0xf83b, 0x10}, {0xf83c, 0x00}, {0xf83d, 0x4e}, {0xf810, 0x04}, | ||
141 | {0xf811, 0x00}, {0xf812, 0x02}, {0xf813, 0x10}, {0xf803, 0x00}, | ||
142 | {0xf814, 0x01}, {0xf815, 0x18}, {0xf816, 0x00}, {0xf817, 0x48}, | ||
143 | {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c}, | ||
144 | {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff}, | ||
145 | {0xf823, 0x07}, {0xf824, 0xff}, {0xf825, 0x03}, {0xf826, 0xff}, | ||
146 | {0xf827, 0x06}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff}, | ||
147 | {0xf82b, 0x0c}, {0xf82c, 0xfd}, {0xf82d, 0x01}, {0xf82e, 0x00}, | ||
148 | {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00}, | ||
149 | {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24}, | ||
150 | {0xf854, 0x00}, {0xf855, 0x18}, {0xf856, 0x00}, {0xf857, 0x3c}, | ||
151 | {0xf858, 0x00}, {0xf859, 0x0c}, {0xf85a, 0x00}, {0xf85b, 0x30}, | ||
152 | {0xf85c, 0x00}, {0xf85d, 0x0c}, {0xf85e, 0x00}, {0xf85f, 0x30}, | ||
153 | {0xf860, 0x00}, {0xf861, 0x48}, {0xf862, 0x01}, {0xf863, 0xdc}, | ||
154 | {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0}, | ||
155 | {0xf868, 0xff}, {0xf869, 0x70}, {0xf86c, 0xff}, {0xf86d, 0x00}, | ||
156 | {0xf86a, 0xff}, {0xf86b, 0x48}, {0xf86e, 0xff}, {0xf86f, 0x00}, | ||
157 | {0xf870, 0x01}, {0xf871, 0xdb}, {0xf872, 0x01}, {0xf873, 0xfa}, | ||
158 | {0xf874, 0x01}, {0xf875, 0xdb}, {0xf876, 0x01}, {0xf877, 0xfa}, | ||
159 | {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff}, | ||
160 | {0xf800, 0x03} | ||
161 | }; | ||
162 | static const struct ucbus_write_cmd icx098bq_start_1[] = { | ||
163 | {0xf5f0, 0x00}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, | ||
164 | {0xf5f4, 0xc0}, | ||
165 | {0xf5f0, 0x49}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, | ||
166 | {0xf5f4, 0xc0}, | ||
167 | {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, | ||
168 | {0xf5f9, 0x00} | ||
169 | }; | ||
170 | |||
171 | static const struct ucbus_write_cmd icx098bq_start_2[] = { | ||
172 | {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x82}, {0xf806, 0x00}, | ||
173 | {0xf807, 0x7f}, {0xf800, 0x03}, | ||
174 | {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x40}, {0xf806, 0x00}, | ||
175 | {0xf807, 0x7f}, {0xf800, 0x03}, | ||
176 | {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xcf}, {0xf806, 0xd0}, | ||
177 | {0xf807, 0x7f}, {0xf800, 0x03}, | ||
178 | {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00}, | ||
179 | {0xf807, 0x7f}, {0xf800, 0x03} | ||
180 | }; | ||
181 | |||
182 | static const struct ucbus_write_cmd lz24bp_start_0[] = { | ||
183 | {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xbe}, | ||
184 | {0xf802, 0xc6}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x06}, | ||
185 | {0xf80a, 0x01}, {0xf80b, 0xfe}, {0xf807, 0x84}, {0xf80c, 0x02}, | ||
186 | {0xf80d, 0xf7}, {0xf80e, 0x03}, {0xf80f, 0x0b}, {0xf81c, 0x00}, | ||
187 | {0xf81d, 0x49}, {0xf81e, 0x03}, {0xf81f, 0x0b}, {0xf83a, 0x00}, | ||
188 | {0xf83b, 0x01}, {0xf83c, 0x00}, {0xf83d, 0x6b}, {0xf810, 0x03}, | ||
189 | {0xf811, 0x10}, {0xf812, 0x02}, {0xf813, 0x6f}, {0xf803, 0x00}, | ||
190 | {0xf814, 0x00}, {0xf815, 0x44}, {0xf816, 0x00}, {0xf817, 0x48}, | ||
191 | {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c}, | ||
192 | {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff}, | ||
193 | {0xf823, 0x07}, {0xf824, 0xfd}, {0xf825, 0x07}, {0xf826, 0xf0}, | ||
194 | {0xf827, 0x0c}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff}, | ||
195 | {0xf82b, 0x0c}, {0xf82c, 0xfc}, {0xf82d, 0x01}, {0xf82e, 0x00}, | ||
196 | {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00}, | ||
197 | {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24}, | ||
198 | {0xf854, 0x00}, {0xf855, 0x0c}, {0xf856, 0x00}, {0xf857, 0x30}, | ||
199 | {0xf858, 0x00}, {0xf859, 0x18}, {0xf85a, 0x00}, {0xf85b, 0x3c}, | ||
200 | {0xf85c, 0x00}, {0xf85d, 0x18}, {0xf85e, 0x00}, {0xf85f, 0x3c}, | ||
201 | {0xf860, 0xff}, {0xf861, 0x37}, {0xf862, 0xff}, {0xf863, 0x1d}, | ||
202 | {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0}, | ||
203 | {0xf868, 0x00}, {0xf869, 0x37}, {0xf86c, 0x02}, {0xf86d, 0x1d}, | ||
204 | {0xf86a, 0x00}, {0xf86b, 0x37}, {0xf86e, 0x02}, {0xf86f, 0x1d}, | ||
205 | {0xf870, 0x01}, {0xf871, 0xc6}, {0xf872, 0x02}, {0xf873, 0x04}, | ||
206 | {0xf874, 0x01}, {0xf875, 0xc6}, {0xf876, 0x02}, {0xf877, 0x04}, | ||
207 | {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff}, | ||
208 | {0xf800, 0x03} | ||
209 | }; | ||
210 | static const struct ucbus_write_cmd lz24bp_start_1_gen[] = { | ||
211 | {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, | ||
212 | {0xf5f4, 0xb3}, | ||
213 | {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, | ||
214 | {0xf5f4, 0xb3}, | ||
215 | {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, | ||
216 | {0xf5f9, 0x00} | ||
217 | }; | ||
218 | |||
219 | static const struct ucbus_write_cmd lz24bp_start_1_clm[] = { | ||
220 | {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88}, | ||
221 | {0xf5f4, 0xc0}, | ||
222 | {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88}, | ||
223 | {0xf5f4, 0xc0}, | ||
224 | {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, | ||
225 | {0xf5f9, 0x00} | ||
226 | }; | ||
227 | |||
228 | static const struct ucbus_write_cmd lz24bp_start_2[] = { | ||
229 | {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x80}, {0xf806, 0x00}, | ||
230 | {0xf807, 0x7f}, {0xf800, 0x03}, | ||
231 | {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x4e}, {0xf806, 0x00}, | ||
232 | {0xf807, 0x7f}, {0xf800, 0x03}, | ||
233 | {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xc0}, {0xf806, 0x48}, | ||
234 | {0xf807, 0x7f}, {0xf800, 0x03}, | ||
235 | {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00}, | ||
236 | {0xf807, 0x7f}, {0xf800, 0x03} | ||
237 | }; | ||
238 | |||
239 | static const struct ucbus_write_cmd mi0360_start_0[] = { | ||
240 | {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0xcc}, {0xf333, 0xcc}, | ||
241 | {0xf334, 0xcc}, {0xf335, 0xcc}, {0xf33f, 0x00} | ||
242 | }; | ||
243 | static const struct i2c_write_cmd mi0360_init_23[] = { | ||
244 | {0x30, 0x0040}, /* reserved - def 0x0005 */ | ||
245 | {0x31, 0x0000}, /* reserved - def 0x002a */ | ||
246 | {0x34, 0x0100}, /* reserved - def 0x0100 */ | ||
247 | {0x3d, 0x068f}, /* reserved - def 0x068f */ | ||
248 | }; | ||
249 | static const struct i2c_write_cmd mi0360_init_24[] = { | ||
250 | {0x03, 0x01e5}, /* window height */ | ||
251 | {0x04, 0x0285}, /* window width */ | ||
252 | }; | ||
253 | static const struct i2c_write_cmd mi0360_init_25[] = { | ||
254 | {0x35, 0x0020}, /* global gain */ | ||
255 | {0x2b, 0x0020}, /* green1 gain */ | ||
256 | {0x2c, 0x002a}, /* blue gain */ | ||
257 | {0x2d, 0x0028}, /* red gain */ | ||
258 | {0x2e, 0x0020}, /* green2 gain */ | ||
259 | }; | ||
260 | static const struct ucbus_write_cmd mi0360_start_1[] = { | ||
261 | {0xf5f0, 0x11}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, | ||
262 | {0xf5f4, 0xa6}, | ||
263 | {0xf5f0, 0x51}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, | ||
264 | {0xf5f4, 0xa6}, | ||
265 | {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, | ||
266 | {0xf5f9, 0x00} | ||
267 | }; | ||
268 | static const struct i2c_write_cmd mi0360_start_2[] = { | ||
269 | {0x62, 0x041d}, /* reserved - def 0x0418 */ | ||
270 | }; | ||
271 | static const struct i2c_write_cmd mi0360_start_3[] = { | ||
272 | {0x05, 0x007b}, /* horiz blanking */ | ||
273 | }; | ||
274 | static const struct i2c_write_cmd mi0360_start_4[] = { | ||
275 | {0x05, 0x03f5}, /* horiz blanking */ | ||
276 | }; | ||
277 | |||
278 | static const struct i2c_write_cmd mt9v111_init_0[] = { | ||
279 | {0x01, 0x0001}, /* select IFP/SOC registers */ | ||
280 | {0x06, 0x300c}, /* operating mode control */ | ||
281 | {0x08, 0xcc00}, /* output format control (RGB) */ | ||
282 | {0x01, 0x0004}, /* select sensor core registers */ | ||
283 | }; | ||
284 | static const struct i2c_write_cmd mt9v111_init_1[] = { | ||
285 | {0x03, 0x01e5}, /* window height */ | ||
286 | {0x04, 0x0285}, /* window width */ | ||
287 | }; | ||
288 | static const struct i2c_write_cmd mt9v111_init_2[] = { | ||
289 | {0x30, 0x7800}, | ||
290 | {0x31, 0x0000}, | ||
291 | {0x07, 0x3002}, /* output control */ | ||
292 | {0x35, 0x0020}, /* global gain */ | ||
293 | {0x2b, 0x0020}, /* green1 gain */ | ||
294 | {0x2c, 0x0020}, /* blue gain */ | ||
295 | {0x2d, 0x0020}, /* red gain */ | ||
296 | {0x2e, 0x0020}, /* green2 gain */ | ||
297 | }; | ||
298 | static const struct ucbus_write_cmd mt9v111_start_1[] = { | ||
299 | {0xf5f0, 0x11}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, | ||
300 | {0xf5f4, 0xaa}, | ||
301 | {0xf5f0, 0x51}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, | ||
302 | {0xf5f4, 0xaa}, | ||
303 | {0xf5fa, 0x00}, {0xf5f6, 0x0a}, {0xf5f7, 0x0a}, {0xf5f8, 0x0a}, | ||
304 | {0xf5f9, 0x0a} | ||
305 | }; | ||
306 | static const struct i2c_write_cmd mt9v111_init_3[] = { | ||
307 | {0x62, 0x0405}, | ||
308 | }; | ||
309 | static const struct i2c_write_cmd mt9v111_init_4[] = { | ||
310 | /* {0x05, 0x00ce}, */ | ||
311 | {0x05, 0x005d}, /* horizontal blanking */ | ||
312 | }; | ||
313 | |||
314 | static const struct ucbus_write_cmd ov7660_start_0[] = { | ||
315 | {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0xc0}, | ||
316 | {0xf334, 0x39}, {0xf335, 0xe7}, {0xf33f, 0x03} | ||
317 | }; | ||
318 | |||
319 | static const struct ucbus_write_cmd ov9630_start_0[] = { | ||
320 | {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0x00}, | ||
321 | {0xf334, 0x3e}, {0xf335, 0xf8}, {0xf33f, 0x03} | ||
322 | }; | ||
323 | |||
324 | /* start parameters indexed by [sensor][mode] */ | ||
325 | static const struct cap_s { | ||
326 | u8 cc_sizeid; | ||
327 | u8 cc_bytes[32]; | ||
328 | } capconfig[4][2] = { | ||
329 | [SENSOR_ICX098BQ] = { | ||
330 | {2, /* Bayer 320x240 */ | ||
331 | {0x05, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee, | ||
332 | 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, | ||
333 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, | ||
334 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, | ||
335 | {4, /* Bayer 640x480 */ | ||
336 | {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee, | ||
337 | 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, | ||
338 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
339 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, | ||
340 | }, | ||
341 | [SENSOR_LZ24BP] = { | ||
342 | {2, /* Bayer 320x240 */ | ||
343 | {0x05, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee, | ||
344 | 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, | ||
345 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
346 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, | ||
347 | {4, /* Bayer 640x480 */ | ||
348 | {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee, | ||
349 | 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, | ||
350 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
351 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, | ||
352 | }, | ||
353 | [SENSOR_MI0360] = { | ||
354 | {2, /* Bayer 320x240 */ | ||
355 | {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, | ||
356 | 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, | ||
357 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
358 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, | ||
359 | {4, /* Bayer 640x480 */ | ||
360 | {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, | ||
361 | 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, | ||
362 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
363 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, | ||
364 | }, | ||
365 | [SENSOR_MT9V111] = { | ||
366 | {2, /* Bayer 320x240 */ | ||
367 | {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, | ||
368 | 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, | ||
369 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
370 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, | ||
371 | {4, /* Bayer 640x480 */ | ||
372 | {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, | ||
373 | 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, | ||
374 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
375 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, | ||
376 | }, | ||
377 | }; | ||
378 | |||
379 | struct sensor_s { | ||
380 | const char *name; | ||
381 | u8 i2c_addr; | ||
382 | u8 i2c_dum; | ||
383 | u8 gpio[5]; | ||
384 | u8 cmd_len; | ||
385 | const struct ucbus_write_cmd *cmd; | ||
386 | }; | ||
387 | |||
388 | static const struct sensor_s sensor_tb[] = { | ||
389 | [SENSOR_ICX098BQ] = { | ||
390 | "icx098bp", | ||
391 | 0x00, 0x00, | ||
392 | {0, | ||
393 | SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, | ||
394 | SQ930_GPIO_DFL_I2C_SDA, | ||
395 | 0, | ||
396 | SQ930_GPIO_RSTBAR | ||
397 | }, | ||
398 | 8, icx098bq_start_0 | ||
399 | }, | ||
400 | [SENSOR_LZ24BP] = { | ||
401 | "lz24bp", | ||
402 | 0x00, 0x00, | ||
403 | {0, | ||
404 | SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, | ||
405 | SQ930_GPIO_DFL_I2C_SDA, | ||
406 | 0, | ||
407 | SQ930_GPIO_RSTBAR | ||
408 | }, | ||
409 | 8, lz24bp_start_0 | ||
410 | }, | ||
411 | [SENSOR_MI0360] = { | ||
412 | "mi0360", | ||
413 | 0x5d, 0x80, | ||
414 | {SQ930_GPIO_RSTBAR, | ||
415 | SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, | ||
416 | SQ930_GPIO_DFL_I2C_SDA, | ||
417 | 0, | ||
418 | 0 | ||
419 | }, | ||
420 | 7, mi0360_start_0 | ||
421 | }, | ||
422 | [SENSOR_MT9V111] = { | ||
423 | "mt9v111", | ||
424 | 0x5c, 0x7f, | ||
425 | {SQ930_GPIO_RSTBAR, | ||
426 | SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, | ||
427 | SQ930_GPIO_DFL_I2C_SDA, | ||
428 | 0, | ||
429 | 0 | ||
430 | }, | ||
431 | 7, mi0360_start_0 | ||
432 | }, | ||
433 | [SENSOR_OV7660] = { | ||
434 | "ov7660", | ||
435 | 0x21, 0x00, | ||
436 | {0, | ||
437 | SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, | ||
438 | SQ930_GPIO_DFL_I2C_SDA, | ||
439 | 0, | ||
440 | SQ930_GPIO_RSTBAR | ||
441 | }, | ||
442 | 7, ov7660_start_0 | ||
443 | }, | ||
444 | [SENSOR_OV9630] = { | ||
445 | "ov9630", | ||
446 | 0x30, 0x00, | ||
447 | {0, | ||
448 | SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL, | ||
449 | SQ930_GPIO_DFL_I2C_SDA, | ||
450 | 0, | ||
451 | SQ930_GPIO_RSTBAR | ||
452 | }, | ||
453 | 7, ov9630_start_0 | ||
454 | }, | ||
455 | }; | ||
456 | |||
457 | static void reg_r(struct gspca_dev *gspca_dev, | ||
458 | u16 value, int len) | ||
459 | { | ||
460 | int ret; | ||
461 | |||
462 | if (gspca_dev->usb_err < 0) | ||
463 | return; | ||
464 | ret = usb_control_msg(gspca_dev->dev, | ||
465 | usb_rcvctrlpipe(gspca_dev->dev, 0), | ||
466 | 0x0c, | ||
467 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
468 | value, 0, gspca_dev->usb_buf, len, | ||
469 | 500); | ||
470 | if (ret < 0) { | ||
471 | err("reg_r %04x failed %d", value, ret); | ||
472 | gspca_dev->usb_err = ret; | ||
473 | } | ||
474 | } | ||
475 | |||
476 | static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) | ||
477 | { | ||
478 | int ret; | ||
479 | |||
480 | if (gspca_dev->usb_err < 0) | ||
481 | return; | ||
482 | PDEBUG(D_USBO, "reg_w v: %04x i: %04x", value, index); | ||
483 | ret = usb_control_msg(gspca_dev->dev, | ||
484 | usb_sndctrlpipe(gspca_dev->dev, 0), | ||
485 | 0x0c, /* request */ | ||
486 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
487 | value, index, NULL, 0, | ||
488 | 500); | ||
489 | msleep(30); | ||
490 | if (ret < 0) { | ||
491 | err("reg_w %04x %04x failed %d", value, index, ret); | ||
492 | gspca_dev->usb_err = ret; | ||
493 | } | ||
494 | } | ||
495 | |||
496 | static void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index, | ||
497 | const u8 *data, int len) | ||
498 | { | ||
499 | int ret; | ||
500 | |||
501 | if (gspca_dev->usb_err < 0) | ||
502 | return; | ||
503 | PDEBUG(D_USBO, "reg_wb v: %04x i: %04x %02x...%02x", | ||
504 | value, index, *data, data[len - 1]); | ||
505 | memcpy(gspca_dev->usb_buf, data, len); | ||
506 | ret = usb_control_msg(gspca_dev->dev, | ||
507 | usb_sndctrlpipe(gspca_dev->dev, 0), | ||
508 | 0x0c, /* request */ | ||
509 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
510 | value, index, gspca_dev->usb_buf, len, | ||
511 | 1000); | ||
512 | msleep(30); | ||
513 | if (ret < 0) { | ||
514 | err("reg_wb %04x %04x failed %d", value, index, ret); | ||
515 | gspca_dev->usb_err = ret; | ||
516 | } | ||
517 | } | ||
518 | |||
519 | static void i2c_write(struct sd *sd, | ||
520 | const struct i2c_write_cmd *cmd, | ||
521 | int ncmds) | ||
522 | { | ||
523 | struct gspca_dev *gspca_dev = &sd->gspca_dev; | ||
524 | const struct sensor_s *sensor; | ||
525 | u16 val, idx; | ||
526 | u8 *buf; | ||
527 | int ret; | ||
528 | |||
529 | if (gspca_dev->usb_err < 0) | ||
530 | return; | ||
531 | |||
532 | sensor = &sensor_tb[sd->sensor]; | ||
533 | |||
534 | val = (sensor->i2c_addr << 8) | SQ930_CTRL_I2C_IO; | ||
535 | idx = (cmd->val & 0xff00) | cmd->reg; | ||
536 | |||
537 | buf = gspca_dev->usb_buf; | ||
538 | *buf++ = sensor->i2c_dum; | ||
539 | *buf++ = cmd->val; | ||
540 | |||
541 | while (--ncmds > 0) { | ||
542 | cmd++; | ||
543 | *buf++ = cmd->reg; | ||
544 | *buf++ = cmd->val >> 8; | ||
545 | *buf++ = sensor->i2c_dum; | ||
546 | *buf++ = cmd->val; | ||
547 | } | ||
548 | |||
549 | PDEBUG(D_USBO, "i2c_w v: %04x i: %04x %02x...%02x", | ||
550 | val, idx, gspca_dev->usb_buf[0], buf[-1]); | ||
551 | ret = usb_control_msg(gspca_dev->dev, | ||
552 | usb_sndctrlpipe(gspca_dev->dev, 0), | ||
553 | 0x0c, /* request */ | ||
554 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
555 | val, idx, | ||
556 | gspca_dev->usb_buf, buf - gspca_dev->usb_buf, | ||
557 | 500); | ||
558 | if (ret < 0) { | ||
559 | err("i2c_write failed %d", ret); | ||
560 | gspca_dev->usb_err = ret; | ||
561 | } | ||
562 | } | ||
563 | |||
564 | static void ucbus_write(struct gspca_dev *gspca_dev, | ||
565 | const struct ucbus_write_cmd *cmd, | ||
566 | int ncmds, | ||
567 | int batchsize) | ||
568 | { | ||
569 | u8 *buf; | ||
570 | u16 val, idx; | ||
571 | int len, ret; | ||
572 | |||
573 | if (gspca_dev->usb_err < 0) | ||
574 | return; | ||
575 | |||
576 | #ifdef GSPCA_DEBUG | ||
577 | if ((batchsize - 1) * 3 > USB_BUF_SZ) { | ||
578 | err("Bug: usb_buf overflow"); | ||
579 | gspca_dev->usb_err = -ENOMEM; | ||
580 | return; | ||
581 | } | ||
582 | #endif | ||
583 | |||
584 | for (;;) { | ||
585 | len = ncmds; | ||
586 | if (len > batchsize) | ||
587 | len = batchsize; | ||
588 | ncmds -= len; | ||
589 | |||
590 | val = (cmd->bw_addr << 8) | SQ930_CTRL_UCBUS_IO; | ||
591 | idx = (cmd->bw_data << 8) | (cmd->bw_addr >> 8); | ||
592 | |||
593 | buf = gspca_dev->usb_buf; | ||
594 | while (--len > 0) { | ||
595 | cmd++; | ||
596 | *buf++ = cmd->bw_addr; | ||
597 | *buf++ = cmd->bw_addr >> 8; | ||
598 | *buf++ = cmd->bw_data; | ||
599 | } | ||
600 | if (buf != gspca_dev->usb_buf) | ||
601 | PDEBUG(D_USBO, "ucbus v: %04x i: %04x %02x...%02x", | ||
602 | val, idx, | ||
603 | gspca_dev->usb_buf[0], buf[-1]); | ||
604 | else | ||
605 | PDEBUG(D_USBO, "ucbus v: %04x i: %04x", | ||
606 | val, idx); | ||
607 | ret = usb_control_msg(gspca_dev->dev, | ||
608 | usb_sndctrlpipe(gspca_dev->dev, 0), | ||
609 | 0x0c, /* request */ | ||
610 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
611 | val, idx, | ||
612 | gspca_dev->usb_buf, buf - gspca_dev->usb_buf, | ||
613 | 500); | ||
614 | if (ret < 0) { | ||
615 | err("ucbus_write failed %d", ret); | ||
616 | gspca_dev->usb_err = ret; | ||
617 | return; | ||
618 | } | ||
619 | msleep(30); | ||
620 | if (ncmds <= 0) | ||
621 | break; | ||
622 | cmd++; | ||
623 | } | ||
624 | } | ||
625 | |||
626 | static void gpio_set(struct sd *sd, u16 val, u16 mask) | ||
627 | { | ||
628 | struct gspca_dev *gspca_dev = &sd->gspca_dev; | ||
629 | |||
630 | if (mask & 0x00ff) { | ||
631 | sd->gpio[0] &= ~mask; | ||
632 | sd->gpio[0] |= val; | ||
633 | reg_w(gspca_dev, 0x0100 | SQ930_CTRL_GPIO, | ||
634 | ~sd->gpio[0] << 8); | ||
635 | } | ||
636 | mask >>= 8; | ||
637 | val >>= 8; | ||
638 | if (mask) { | ||
639 | sd->gpio[1] &= ~mask; | ||
640 | sd->gpio[1] |= val; | ||
641 | reg_w(gspca_dev, 0x0300 | SQ930_CTRL_GPIO, | ||
642 | ~sd->gpio[1] << 8); | ||
643 | } | ||
644 | } | ||
645 | |||
646 | static void gpio_init(struct sd *sd, | ||
647 | const u8 *gpio) | ||
648 | { | ||
649 | gpio_set(sd, *gpio++, 0x000f); | ||
650 | gpio_set(sd, *gpio++, 0x000f); | ||
651 | gpio_set(sd, *gpio++, 0x000f); | ||
652 | gpio_set(sd, *gpio++, 0x000f); | ||
653 | gpio_set(sd, *gpio, 0x000f); | ||
654 | } | ||
655 | |||
656 | static void bridge_init(struct sd *sd) | ||
657 | { | ||
658 | static const struct ucbus_write_cmd clkfreq_cmd = { | ||
659 | 0xf031, 0 /* SQ930_CLKFREQ_60MHZ */ | ||
660 | }; | ||
661 | |||
662 | ucbus_write(&sd->gspca_dev, &clkfreq_cmd, 1, 1); | ||
663 | |||
664 | gpio_set(sd, SQ930_GPIO_POWER, 0xff00); | ||
665 | } | ||
666 | |||
667 | static void cmos_probe(struct gspca_dev *gspca_dev) | ||
668 | { | ||
669 | struct sd *sd = (struct sd *) gspca_dev; | ||
670 | int i; | ||
671 | const struct sensor_s *sensor; | ||
672 | static const u8 probe_order[] = { | ||
673 | /* SENSOR_LZ24BP, (tested as ccd) */ | ||
674 | SENSOR_OV9630, | ||
675 | SENSOR_MI0360, | ||
676 | SENSOR_OV7660, | ||
677 | SENSOR_MT9V111, | ||
678 | }; | ||
679 | |||
680 | for (i = 0; i < ARRAY_SIZE(probe_order); i++) { | ||
681 | sensor = &sensor_tb[probe_order[i]]; | ||
682 | ucbus_write(&sd->gspca_dev, sensor->cmd, sensor->cmd_len, 8); | ||
683 | gpio_init(sd, sensor->gpio); | ||
684 | msleep(100); | ||
685 | reg_r(gspca_dev, (sensor->i2c_addr << 8) | 0x001c, 1); | ||
686 | msleep(100); | ||
687 | if (gspca_dev->usb_buf[0] != 0) | ||
688 | break; | ||
689 | } | ||
690 | if (i >= ARRAY_SIZE(probe_order)) { | ||
691 | err("Unknown sensor"); | ||
692 | gspca_dev->usb_err = -EINVAL; | ||
693 | return; | ||
694 | } | ||
695 | sd->sensor = probe_order[i]; | ||
696 | switch (sd->sensor) { | ||
697 | case SENSOR_OV7660: | ||
698 | case SENSOR_OV9630: | ||
699 | err("Sensor %s not yet treated", sensor_tb[sd->sensor].name); | ||
700 | gspca_dev->usb_err = -EINVAL; | ||
701 | break; | ||
702 | } | ||
703 | } | ||
704 | |||
705 | static void mt9v111_init(struct gspca_dev *gspca_dev) | ||
706 | { | ||
707 | int i, nwait; | ||
708 | static const u8 cmd_001b[] = { | ||
709 | 0x00, 0x3b, 0xf6, 0x01, 0x03, 0x02, 0x00, 0x00, | ||
710 | 0x00, 0x00, 0x00 | ||
711 | }; | ||
712 | static const u8 cmd_011b[][7] = { | ||
713 | {0x10, 0x01, 0x66, 0x08, 0x00, 0x00, 0x00}, | ||
714 | {0x01, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x00}, | ||
715 | {0x20, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00}, | ||
716 | {0x02, 0x01, 0xae, 0x01, 0x00, 0x00, 0x00}, | ||
717 | }; | ||
718 | |||
719 | reg_wb(gspca_dev, 0x001b, 0x0000, cmd_001b, sizeof cmd_001b); | ||
720 | for (i = 0; i < ARRAY_SIZE(cmd_011b); i++) { | ||
721 | reg_wb(gspca_dev, 0x001b, 0x0000, cmd_011b[i], | ||
722 | ARRAY_SIZE(cmd_011b[0])); | ||
723 | msleep(400); | ||
724 | nwait = 20; | ||
725 | for (;;) { | ||
726 | reg_r(gspca_dev, 0x031b, 1); | ||
727 | if (gspca_dev->usb_buf[0] == 0 | ||
728 | || gspca_dev->usb_err != 0) | ||
729 | break; | ||
730 | if (--nwait < 0) { | ||
731 | PDEBUG(D_PROBE, "mt9v111_init timeout"); | ||
732 | gspca_dev->usb_err = -ETIME; | ||
733 | return; | ||
734 | } | ||
735 | msleep(50); | ||
736 | } | ||
737 | } | ||
738 | } | ||
739 | |||
740 | static void global_init(struct sd *sd, int first_time) | ||
741 | { | ||
742 | switch (sd->sensor) { | ||
743 | case SENSOR_ICX098BQ: | ||
744 | if (first_time) | ||
745 | ucbus_write(&sd->gspca_dev, | ||
746 | icx098bq_start_0, | ||
747 | 8, 8); | ||
748 | gpio_init(sd, sensor_tb[sd->sensor].gpio); | ||
749 | break; | ||
750 | case SENSOR_LZ24BP: | ||
751 | if (sd->type != Creative_live_motion) | ||
752 | gpio_set(sd, SQ930_GPIO_EXTRA1, 0x00ff); | ||
753 | else | ||
754 | gpio_set(sd, 0, 0x00ff); | ||
755 | msleep(50); | ||
756 | if (first_time) | ||
757 | ucbus_write(&sd->gspca_dev, | ||
758 | lz24bp_start_0, | ||
759 | 8, 8); | ||
760 | gpio_init(sd, sensor_tb[sd->sensor].gpio); | ||
761 | break; | ||
762 | case SENSOR_MI0360: | ||
763 | if (first_time) | ||
764 | ucbus_write(&sd->gspca_dev, | ||
765 | mi0360_start_0, | ||
766 | ARRAY_SIZE(mi0360_start_0), | ||
767 | 8); | ||
768 | gpio_init(sd, sensor_tb[sd->sensor].gpio); | ||
769 | gpio_set(sd, SQ930_GPIO_EXTRA2, SQ930_GPIO_EXTRA2); | ||
770 | break; | ||
771 | default: | ||
772 | /* case SENSOR_MT9V111: */ | ||
773 | if (first_time) | ||
774 | mt9v111_init(&sd->gspca_dev); | ||
775 | else | ||
776 | gpio_init(sd, sensor_tb[sd->sensor].gpio); | ||
777 | break; | ||
778 | } | ||
779 | } | ||
780 | |||
781 | static void lz24bp_ppl(struct sd *sd, u16 ppl) | ||
782 | { | ||
783 | struct ucbus_write_cmd cmds[2] = { | ||
784 | {0xf810, ppl >> 8}, | ||
785 | {0xf811, ppl} | ||
786 | }; | ||
787 | |||
788 | ucbus_write(&sd->gspca_dev, cmds, ARRAY_SIZE(cmds), 2); | ||
789 | } | ||
790 | |||
791 | static void setexposure(struct gspca_dev *gspca_dev) | ||
792 | { | ||
793 | struct sd *sd = (struct sd *) gspca_dev; | ||
794 | int i, integclks, intstartclk, frameclks, min_frclk; | ||
795 | const struct sensor_s *sensor; | ||
796 | u16 cmd; | ||
797 | u8 buf[15]; | ||
798 | |||
799 | integclks = sd->expo; | ||
800 | i = 0; | ||
801 | cmd = SQ930_CTRL_SET_EXPOSURE; | ||
802 | |||
803 | switch (sd->sensor) { | ||
804 | case SENSOR_ICX098BQ: /* ccd */ | ||
805 | case SENSOR_LZ24BP: | ||
806 | min_frclk = sd->sensor == SENSOR_ICX098BQ ? 0x210 : 0x26f; | ||
807 | if (integclks >= min_frclk) { | ||
808 | intstartclk = 0; | ||
809 | frameclks = integclks; | ||
810 | } else { | ||
811 | intstartclk = min_frclk - integclks; | ||
812 | frameclks = min_frclk; | ||
813 | } | ||
814 | buf[i++] = intstartclk >> 8; | ||
815 | buf[i++] = intstartclk; | ||
816 | buf[i++] = frameclks >> 8; | ||
817 | buf[i++] = frameclks; | ||
818 | buf[i++] = sd->gain; | ||
819 | break; | ||
820 | default: /* cmos */ | ||
821 | /* case SENSOR_MI0360: */ | ||
822 | /* case SENSOR_MT9V111: */ | ||
823 | cmd |= 0x0100; | ||
824 | sensor = &sensor_tb[sd->sensor]; | ||
825 | buf[i++] = sensor->i2c_addr; /* i2c_slave_addr */ | ||
826 | buf[i++] = 0x08; /* 2 * ni2c */ | ||
827 | buf[i++] = 0x09; /* reg = shutter width */ | ||
828 | buf[i++] = integclks >> 8; /* val H */ | ||
829 | buf[i++] = sensor->i2c_dum; | ||
830 | buf[i++] = integclks; /* val L */ | ||
831 | buf[i++] = 0x35; /* reg = global gain */ | ||
832 | buf[i++] = 0x00; /* val H */ | ||
833 | buf[i++] = sensor->i2c_dum; | ||
834 | buf[i++] = 0x80 + sd->gain / 2; /* val L */ | ||
835 | buf[i++] = 0x00; | ||
836 | buf[i++] = 0x00; | ||
837 | buf[i++] = 0x00; | ||
838 | buf[i++] = 0x00; | ||
839 | buf[i++] = 0x83; | ||
840 | break; | ||
841 | } | ||
842 | reg_wb(gspca_dev, cmd, 0, buf, i); | ||
843 | } | ||
844 | |||
845 | /* This function is called at probe time just before sd_init */ | ||
846 | static int sd_config(struct gspca_dev *gspca_dev, | ||
847 | const struct usb_device_id *id) | ||
848 | { | ||
849 | struct sd *sd = (struct sd *) gspca_dev; | ||
850 | struct cam *cam = &gspca_dev->cam; | ||
851 | |||
852 | sd->sensor = id->driver_info >> 8; | ||
853 | sd->type = id->driver_info; | ||
854 | |||
855 | cam->cam_mode = vga_mode; | ||
856 | cam->nmodes = ARRAY_SIZE(vga_mode); | ||
857 | |||
858 | cam->bulk = 1; | ||
859 | |||
860 | sd->gain = GAIN_DEF; | ||
861 | sd->expo = EXPO_DEF; | ||
862 | |||
863 | return 0; | ||
864 | } | ||
865 | |||
866 | /* this function is called at probe and resume time */ | ||
867 | static int sd_init(struct gspca_dev *gspca_dev) | ||
868 | { | ||
869 | struct sd *sd = (struct sd *) gspca_dev; | ||
870 | |||
871 | sd->gpio[0] = sd->gpio[1] = 0xff; /* force gpio rewrite */ | ||
872 | |||
873 | /*fixme: is this needed for icx098bp and mi0360? | ||
874 | if (sd->sensor != SENSOR_LZ24BP) | ||
875 | reg_w(gspca_dev, SQ930_CTRL_RESET, 0x0000); | ||
876 | */ | ||
877 | |||
878 | reg_r(gspca_dev, SQ930_CTRL_GET_DEV_INFO, 8); | ||
879 | if (gspca_dev->usb_err < 0) | ||
880 | return gspca_dev->usb_err; | ||
881 | |||
882 | /* it returns: | ||
883 | * 03 00 12 93 0b f6 c9 00 live! ultra | ||
884 | * 03 00 07 93 0b f6 ca 00 live! ultra for notebook | ||
885 | * 03 00 12 93 0b fe c8 00 Trust WB-3500T | ||
886 | * 02 00 06 93 0b fe c8 00 Joy-IT 318S | ||
887 | * 03 00 12 93 0b f6 cf 00 icam tracer - sensor icx098bq | ||
888 | * 02 00 12 93 0b fe cf 00 ProQ Motion Webcam | ||
889 | * | ||
890 | * byte | ||
891 | * 0: 02 = usb 1.0 (12Mbit) / 03 = usb2.0 (480Mbit) | ||
892 | * 1: 00 | ||
893 | * 2: 06 / 07 / 12 = mode webcam? firmware?? | ||
894 | * 3: 93 chip = 930b (930b or 930c) | ||
895 | * 4: 0b | ||
896 | * 5: f6 = cdd (icx098bq, lz24bp) / fe or de = cmos (i2c) (other sensors) | ||
897 | * 6: c8 / c9 / ca / cf = mode webcam?, sensor? webcam? | ||
898 | * 7: 00 | ||
899 | */ | ||
900 | PDEBUG(D_PROBE, "info: %02x %02x %02x %02x %02x %02x %02x %02x", | ||
901 | gspca_dev->usb_buf[0], | ||
902 | gspca_dev->usb_buf[1], | ||
903 | gspca_dev->usb_buf[2], | ||
904 | gspca_dev->usb_buf[3], | ||
905 | gspca_dev->usb_buf[4], | ||
906 | gspca_dev->usb_buf[5], | ||
907 | gspca_dev->usb_buf[6], | ||
908 | gspca_dev->usb_buf[7]); | ||
909 | |||
910 | bridge_init(sd); | ||
911 | |||
912 | if (sd->sensor == SENSOR_MI0360) { | ||
913 | |||
914 | /* no sensor probe for icam tracer */ | ||
915 | if (gspca_dev->usb_buf[5] == 0xf6) /* if ccd */ | ||
916 | sd->sensor = SENSOR_ICX098BQ; | ||
917 | else | ||
918 | cmos_probe(gspca_dev); | ||
919 | } | ||
920 | if (gspca_dev->usb_err >= 0) { | ||
921 | PDEBUG(D_PROBE, "Sensor %s", sensor_tb[sd->sensor].name); | ||
922 | global_init(sd, 1); | ||
923 | } | ||
924 | return gspca_dev->usb_err; | ||
925 | } | ||
926 | |||
927 | /* send the start/stop commands to the webcam */ | ||
928 | static void send_start(struct gspca_dev *gspca_dev) | ||
929 | { | ||
930 | struct sd *sd = (struct sd *) gspca_dev; | ||
931 | const struct cap_s *cap; | ||
932 | int mode; | ||
933 | |||
934 | mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; | ||
935 | cap = &capconfig[sd->sensor][mode]; | ||
936 | reg_wb(gspca_dev, 0x0900 | SQ930_CTRL_CAP_START, | ||
937 | 0x0a00 | cap->cc_sizeid, | ||
938 | cap->cc_bytes, 32); | ||
939 | } | ||
940 | |||
941 | static void send_stop(struct gspca_dev *gspca_dev) | ||
942 | { | ||
943 | reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0); | ||
944 | } | ||
945 | |||
946 | /* function called at start time before URB creation */ | ||
947 | static int sd_isoc_init(struct gspca_dev *gspca_dev) | ||
948 | { | ||
949 | struct sd *sd = (struct sd *) gspca_dev; | ||
950 | |||
951 | gspca_dev->cam.bulk_nurbs = 1; /* there must be one URB only */ | ||
952 | sd->do_ctrl = 0; | ||
953 | gspca_dev->cam.bulk_size = gspca_dev->width * gspca_dev->height + 8; | ||
954 | return 0; | ||
955 | } | ||
956 | |||
957 | /* start the capture */ | ||
958 | static int sd_start(struct gspca_dev *gspca_dev) | ||
959 | { | ||
960 | struct sd *sd = (struct sd *) gspca_dev; | ||
961 | int mode; | ||
962 | |||
963 | bridge_init(sd); | ||
964 | global_init(sd, 0); | ||
965 | msleep(100); | ||
966 | |||
967 | switch (sd->sensor) { | ||
968 | case SENSOR_ICX098BQ: | ||
969 | ucbus_write(gspca_dev, icx098bq_start_0, | ||
970 | ARRAY_SIZE(icx098bq_start_0), | ||
971 | 8); | ||
972 | ucbus_write(gspca_dev, icx098bq_start_1, | ||
973 | ARRAY_SIZE(icx098bq_start_1), | ||
974 | 5); | ||
975 | ucbus_write(gspca_dev, icx098bq_start_2, | ||
976 | ARRAY_SIZE(icx098bq_start_2), | ||
977 | 6); | ||
978 | msleep(50); | ||
979 | |||
980 | /* 1st start */ | ||
981 | send_start(gspca_dev); | ||
982 | gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff); | ||
983 | msleep(70); | ||
984 | reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000); | ||
985 | gpio_set(sd, 0x7f, 0x00ff); | ||
986 | |||
987 | /* 2nd start */ | ||
988 | send_start(gspca_dev); | ||
989 | gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff); | ||
990 | goto out; | ||
991 | case SENSOR_LZ24BP: | ||
992 | ucbus_write(gspca_dev, lz24bp_start_0, | ||
993 | ARRAY_SIZE(lz24bp_start_0), | ||
994 | 8); | ||
995 | if (sd->type != Creative_live_motion) | ||
996 | ucbus_write(gspca_dev, lz24bp_start_1_gen, | ||
997 | ARRAY_SIZE(lz24bp_start_1_gen), | ||
998 | 5); | ||
999 | else | ||
1000 | ucbus_write(gspca_dev, lz24bp_start_1_clm, | ||
1001 | ARRAY_SIZE(lz24bp_start_1_clm), | ||
1002 | 5); | ||
1003 | ucbus_write(gspca_dev, lz24bp_start_2, | ||
1004 | ARRAY_SIZE(lz24bp_start_2), | ||
1005 | 6); | ||
1006 | mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; | ||
1007 | lz24bp_ppl(sd, mode == 1 ? 0x0564 : 0x0310); | ||
1008 | msleep(10); | ||
1009 | break; | ||
1010 | case SENSOR_MI0360: | ||
1011 | ucbus_write(gspca_dev, mi0360_start_0, | ||
1012 | ARRAY_SIZE(mi0360_start_0), | ||
1013 | 8); | ||
1014 | i2c_write(sd, mi0360_init_23, | ||
1015 | ARRAY_SIZE(mi0360_init_23)); | ||
1016 | i2c_write(sd, mi0360_init_24, | ||
1017 | ARRAY_SIZE(mi0360_init_24)); | ||
1018 | i2c_write(sd, mi0360_init_25, | ||
1019 | ARRAY_SIZE(mi0360_init_25)); | ||
1020 | ucbus_write(gspca_dev, mi0360_start_1, | ||
1021 | ARRAY_SIZE(mi0360_start_1), | ||
1022 | 5); | ||
1023 | i2c_write(sd, mi0360_start_2, | ||
1024 | ARRAY_SIZE(mi0360_start_2)); | ||
1025 | i2c_write(sd, mi0360_start_3, | ||
1026 | ARRAY_SIZE(mi0360_start_3)); | ||
1027 | |||
1028 | /* 1st start */ | ||
1029 | send_start(gspca_dev); | ||
1030 | msleep(60); | ||
1031 | send_stop(gspca_dev); | ||
1032 | |||
1033 | i2c_write(sd, | ||
1034 | mi0360_start_4, ARRAY_SIZE(mi0360_start_4)); | ||
1035 | break; | ||
1036 | default: | ||
1037 | /* case SENSOR_MT9V111: */ | ||
1038 | ucbus_write(gspca_dev, mi0360_start_0, | ||
1039 | ARRAY_SIZE(mi0360_start_0), | ||
1040 | 8); | ||
1041 | i2c_write(sd, mt9v111_init_0, | ||
1042 | ARRAY_SIZE(mt9v111_init_0)); | ||
1043 | i2c_write(sd, mt9v111_init_1, | ||
1044 | ARRAY_SIZE(mt9v111_init_1)); | ||
1045 | i2c_write(sd, mt9v111_init_2, | ||
1046 | ARRAY_SIZE(mt9v111_init_2)); | ||
1047 | ucbus_write(gspca_dev, mt9v111_start_1, | ||
1048 | ARRAY_SIZE(mt9v111_start_1), | ||
1049 | 5); | ||
1050 | i2c_write(sd, mt9v111_init_3, | ||
1051 | ARRAY_SIZE(mt9v111_init_3)); | ||
1052 | i2c_write(sd, mt9v111_init_4, | ||
1053 | ARRAY_SIZE(mt9v111_init_4)); | ||
1054 | break; | ||
1055 | } | ||
1056 | |||
1057 | send_start(gspca_dev); | ||
1058 | out: | ||
1059 | msleep(1000); | ||
1060 | |||
1061 | if (sd->sensor == SENSOR_MT9V111) | ||
1062 | gpio_set(sd, SQ930_GPIO_DFL_LED, SQ930_GPIO_DFL_LED); | ||
1063 | |||
1064 | sd->do_ctrl = 1; /* set the exposure */ | ||
1065 | |||
1066 | return gspca_dev->usb_err; | ||
1067 | } | ||
1068 | |||
1069 | static void sd_stopN(struct gspca_dev *gspca_dev) | ||
1070 | { | ||
1071 | struct sd *sd = (struct sd *) gspca_dev; | ||
1072 | |||
1073 | if (sd->sensor == SENSOR_MT9V111) | ||
1074 | gpio_set(sd, 0, SQ930_GPIO_DFL_LED); | ||
1075 | send_stop(gspca_dev); | ||
1076 | } | ||
1077 | |||
1078 | /* function called when the application gets a new frame */ | ||
1079 | /* It sets the exposure if required and restart the bulk transfer. */ | ||
1080 | static void sd_dq_callback(struct gspca_dev *gspca_dev) | ||
1081 | { | ||
1082 | struct sd *sd = (struct sd *) gspca_dev; | ||
1083 | int ret; | ||
1084 | |||
1085 | if (!sd->do_ctrl || gspca_dev->cam.bulk_nurbs != 0) | ||
1086 | return; | ||
1087 | sd->do_ctrl = 0; | ||
1088 | |||
1089 | setexposure(gspca_dev); | ||
1090 | |||
1091 | gspca_dev->cam.bulk_nurbs = 1; | ||
1092 | ret = usb_submit_urb(gspca_dev->urb[0], GFP_ATOMIC); | ||
1093 | if (ret < 0) | ||
1094 | err("sd_dq_callback() err %d", ret); | ||
1095 | |||
1096 | /* wait a little time, otherwise the webcam crashes */ | ||
1097 | msleep(100); | ||
1098 | } | ||
1099 | |||
1100 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | ||
1101 | u8 *data, /* isoc packet */ | ||
1102 | int len) /* iso packet length */ | ||
1103 | { | ||
1104 | struct sd *sd = (struct sd *) gspca_dev; | ||
1105 | |||
1106 | if (sd->do_ctrl) | ||
1107 | gspca_dev->cam.bulk_nurbs = 0; | ||
1108 | gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); | ||
1109 | gspca_frame_add(gspca_dev, INTER_PACKET, data, len - 8); | ||
1110 | gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); | ||
1111 | } | ||
1112 | |||
1113 | static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) | ||
1114 | { | ||
1115 | struct sd *sd = (struct sd *) gspca_dev; | ||
1116 | |||
1117 | sd->gain = val; | ||
1118 | if (gspca_dev->streaming) | ||
1119 | sd->do_ctrl = 1; | ||
1120 | return 0; | ||
1121 | } | ||
1122 | |||
1123 | static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) | ||
1124 | { | ||
1125 | struct sd *sd = (struct sd *) gspca_dev; | ||
1126 | |||
1127 | *val = sd->gain; | ||
1128 | return 0; | ||
1129 | } | ||
1130 | static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val) | ||
1131 | { | ||
1132 | struct sd *sd = (struct sd *) gspca_dev; | ||
1133 | |||
1134 | sd->expo = val; | ||
1135 | if (gspca_dev->streaming) | ||
1136 | sd->do_ctrl = 1; | ||
1137 | return 0; | ||
1138 | } | ||
1139 | |||
1140 | static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val) | ||
1141 | { | ||
1142 | struct sd *sd = (struct sd *) gspca_dev; | ||
1143 | |||
1144 | *val = sd->expo; | ||
1145 | return 0; | ||
1146 | } | ||
1147 | |||
1148 | /* sub-driver description */ | ||
1149 | static const struct sd_desc sd_desc = { | ||
1150 | .name = MODULE_NAME, | ||
1151 | .ctrls = sd_ctrls, | ||
1152 | .nctrls = ARRAY_SIZE(sd_ctrls), | ||
1153 | .config = sd_config, | ||
1154 | .init = sd_init, | ||
1155 | .isoc_init = sd_isoc_init, | ||
1156 | .start = sd_start, | ||
1157 | .stopN = sd_stopN, | ||
1158 | .pkt_scan = sd_pkt_scan, | ||
1159 | .dq_callback = sd_dq_callback, | ||
1160 | }; | ||
1161 | |||
1162 | /* Table of supported USB devices */ | ||
1163 | #define ST(sensor, type) \ | ||
1164 | .driver_info = (SENSOR_ ## sensor << 8) \ | ||
1165 | | (type) | ||
1166 | static const struct usb_device_id device_table[] = { | ||
1167 | {USB_DEVICE(0x041e, 0x4038), ST(MI0360, 0)}, | ||
1168 | {USB_DEVICE(0x041e, 0x403c), ST(LZ24BP, 0)}, | ||
1169 | {USB_DEVICE(0x041e, 0x403d), ST(LZ24BP, 0)}, | ||
1170 | {USB_DEVICE(0x041e, 0x4041), ST(LZ24BP, Creative_live_motion)}, | ||
1171 | {USB_DEVICE(0x2770, 0x930b), ST(MI0360, 0)}, | ||
1172 | {USB_DEVICE(0x2770, 0x930c), ST(MI0360, 0)}, | ||
1173 | {} | ||
1174 | }; | ||
1175 | MODULE_DEVICE_TABLE(usb, device_table); | ||
1176 | |||
1177 | |||
1178 | /* -- device connect -- */ | ||
1179 | static int sd_probe(struct usb_interface *intf, | ||
1180 | const struct usb_device_id *id) | ||
1181 | { | ||
1182 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | ||
1183 | THIS_MODULE); | ||
1184 | } | ||
1185 | |||
1186 | static struct usb_driver sd_driver = { | ||
1187 | .name = MODULE_NAME, | ||
1188 | .id_table = device_table, | ||
1189 | .probe = sd_probe, | ||
1190 | .disconnect = gspca_disconnect, | ||
1191 | #ifdef CONFIG_PM | ||
1192 | .suspend = gspca_suspend, | ||
1193 | .resume = gspca_resume, | ||
1194 | #endif | ||
1195 | }; | ||
1196 | |||
1197 | /* -- module insert / remove -- */ | ||
1198 | static int __init sd_mod_init(void) | ||
1199 | { | ||
1200 | return usb_register(&sd_driver); | ||
1201 | } | ||
1202 | static void __exit sd_mod_exit(void) | ||
1203 | { | ||
1204 | usb_deregister(&sd_driver); | ||
1205 | } | ||
1206 | |||
1207 | module_init(sd_mod_init); | ||
1208 | module_exit(sd_mod_exit); | ||