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