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