diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/media/video/tegra/ov5650.c | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'drivers/media/video/tegra/ov5650.c')
-rw-r--r-- | drivers/media/video/tegra/ov5650.c | 1520 |
1 files changed, 1520 insertions, 0 deletions
diff --git a/drivers/media/video/tegra/ov5650.c b/drivers/media/video/tegra/ov5650.c new file mode 100644 index 00000000000..3adb46a3bb8 --- /dev/null +++ b/drivers/media/video/tegra/ov5650.c | |||
@@ -0,0 +1,1520 @@ | |||
1 | /* | ||
2 | * ov5650.c - ov5650 sensor driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Google Inc. | ||
5 | * | ||
6 | * Contributors: | ||
7 | * Rebecca Schultz Zavin <rebecca@android.com> | ||
8 | * | ||
9 | * Leverage OV9640.c | ||
10 | * | ||
11 | * This file is licensed under the terms of the GNU General Public License | ||
12 | * version 2. This program is licensed "as is" without any warranty of any | ||
13 | * kind, whether express or implied. | ||
14 | */ | ||
15 | |||
16 | #include <linux/delay.h> | ||
17 | #include <linux/fs.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/miscdevice.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/uaccess.h> | ||
22 | #include <media/ov5650.h> | ||
23 | #include <media/tegra_camera.h> | ||
24 | |||
25 | #define SIZEOF_I2C_TRANSBUF 32 | ||
26 | |||
27 | struct ov5650_reg { | ||
28 | u16 addr; | ||
29 | u16 val; | ||
30 | }; | ||
31 | |||
32 | struct ov5650_sensor { | ||
33 | struct i2c_client *i2c_client; | ||
34 | struct ov5650_platform_data *pdata; | ||
35 | }; | ||
36 | |||
37 | struct ov5650_info { | ||
38 | int mode; | ||
39 | enum StereoCameraMode camera_mode; | ||
40 | struct ov5650_sensor left; | ||
41 | struct ov5650_sensor right; | ||
42 | u8 i2c_trans_buf[SIZEOF_I2C_TRANSBUF]; | ||
43 | }; | ||
44 | |||
45 | static struct ov5650_info *stereo_ov5650_info; | ||
46 | |||
47 | #define OV5650_TABLE_WAIT_MS 0 | ||
48 | #define OV5650_TABLE_END 1 | ||
49 | #define OV5650_MAX_RETRIES 3 | ||
50 | |||
51 | static struct ov5650_reg tp_none_seq[] = { | ||
52 | {0x5046, 0x00}, | ||
53 | {OV5650_TABLE_END, 0x0000} | ||
54 | }; | ||
55 | |||
56 | static struct ov5650_reg tp_cbars_seq[] = { | ||
57 | {0x503D, 0xC0}, | ||
58 | {0x503E, 0x00}, | ||
59 | {0x5046, 0x01}, | ||
60 | {OV5650_TABLE_END, 0x0000} | ||
61 | }; | ||
62 | |||
63 | static struct ov5650_reg tp_checker_seq[] = { | ||
64 | {0x503D, 0xC0}, | ||
65 | {0x503E, 0x0A}, | ||
66 | {0x5046, 0x01}, | ||
67 | {OV5650_TABLE_END, 0x0000} | ||
68 | }; | ||
69 | |||
70 | static struct ov5650_reg *test_pattern_modes[] = { | ||
71 | tp_none_seq, | ||
72 | tp_cbars_seq, | ||
73 | tp_checker_seq, | ||
74 | }; | ||
75 | |||
76 | static struct ov5650_reg reset_seq[] = { | ||
77 | {0x3008, 0x82}, | ||
78 | {OV5650_TABLE_WAIT_MS, 5}, | ||
79 | {0x3008, 0x42}, | ||
80 | {OV5650_TABLE_WAIT_MS, 5}, | ||
81 | {OV5650_TABLE_END, 0x0000}, | ||
82 | }; | ||
83 | |||
84 | static struct ov5650_reg mode_start[] = { | ||
85 | {0x3103, 0x93}, | ||
86 | {0x3017, 0xff}, | ||
87 | {0x3018, 0xfc}, | ||
88 | |||
89 | {0x3600, 0x50}, | ||
90 | {0x3601, 0x0d}, | ||
91 | {0x3604, 0x50}, | ||
92 | {0x3605, 0x04}, | ||
93 | {0x3606, 0x3f}, | ||
94 | {0x3612, 0x1a}, | ||
95 | {0x3630, 0x22}, | ||
96 | {0x3631, 0x22}, | ||
97 | {0x3702, 0x3a}, | ||
98 | {0x3704, 0x18}, | ||
99 | {0x3705, 0xda}, | ||
100 | {0x3706, 0x41}, | ||
101 | {0x370a, 0x80}, | ||
102 | {0x370b, 0x40}, | ||
103 | {0x370e, 0x00}, | ||
104 | {0x3710, 0x28}, | ||
105 | {0x3712, 0x13}, | ||
106 | {0x3830, 0x50}, | ||
107 | {0x3a18, 0x00}, | ||
108 | {0x3a19, 0xf8}, | ||
109 | {0x3a00, 0x38}, | ||
110 | |||
111 | |||
112 | {0x3603, 0xa7}, | ||
113 | {0x3615, 0x50}, | ||
114 | {0x3620, 0x56}, | ||
115 | {0x3810, 0x00}, | ||
116 | {0x3836, 0x00}, | ||
117 | {0x3a1a, 0x06}, | ||
118 | {0x4000, 0x01}, | ||
119 | {0x401c, 0x48}, | ||
120 | {0x401d, 0x08}, | ||
121 | {0x5000, 0x00}, | ||
122 | {0x5001, 0x00}, | ||
123 | {0x5002, 0x00}, | ||
124 | {0x503d, 0x00}, | ||
125 | {0x5046, 0x00}, | ||
126 | |||
127 | {0x300f, 0x8f}, | ||
128 | |||
129 | {0x3010, 0x10}, | ||
130 | {0x3011, 0x14}, | ||
131 | {0x3012, 0x02}, | ||
132 | {0x3815, 0x82}, | ||
133 | {0x3503, 0x33}, | ||
134 | {0x3613, 0x44}, | ||
135 | {OV5650_TABLE_END, 0x0}, | ||
136 | }; | ||
137 | |||
138 | static struct ov5650_reg mode_2592x1944[] = { | ||
139 | {0x3621, 0x2f}, | ||
140 | |||
141 | {0x3632, 0x55}, | ||
142 | {0x3703, 0xe6}, | ||
143 | {0x370c, 0xa0}, | ||
144 | {0x370d, 0x04}, | ||
145 | {0x3713, 0x2f}, | ||
146 | {0x3800, 0x02}, | ||
147 | {0x3801, 0x58}, | ||
148 | {0x3802, 0x00}, | ||
149 | {0x3803, 0x0c}, | ||
150 | {0x3804, 0x0a}, | ||
151 | {0x3805, 0x20}, | ||
152 | {0x3806, 0x07}, | ||
153 | {0x3807, 0xa0}, | ||
154 | {0x3808, 0x0a}, | ||
155 | |||
156 | {0x3809, 0x20}, | ||
157 | |||
158 | {0x380a, 0x07}, | ||
159 | |||
160 | {0x380b, 0xa0}, | ||
161 | |||
162 | {0x380c, 0x0c}, | ||
163 | |||
164 | {0x380d, 0xb4}, | ||
165 | |||
166 | {0x380e, 0x07}, | ||
167 | |||
168 | {0x380f, 0xb0}, | ||
169 | |||
170 | {0x3818, 0xc0}, | ||
171 | {0x381a, 0x3c}, | ||
172 | {0x3a0d, 0x06}, | ||
173 | {0x3c01, 0x00}, | ||
174 | {0x3007, 0x3f}, | ||
175 | {0x5059, 0x80}, | ||
176 | {0x3003, 0x03}, | ||
177 | {0x3500, 0x00}, | ||
178 | {0x3501, 0x7a}, | ||
179 | |||
180 | {0x3502, 0xd0}, | ||
181 | |||
182 | {0x350a, 0x00}, | ||
183 | {0x350b, 0x00}, | ||
184 | {0x401d, 0x08}, | ||
185 | {0x4801, 0x0f}, | ||
186 | {0x300e, 0x0c}, | ||
187 | {0x4803, 0x50}, | ||
188 | {0x4800, 0x34}, | ||
189 | {OV5650_TABLE_END, 0x0000} | ||
190 | }; | ||
191 | |||
192 | static struct ov5650_reg mode_1296x972[] = { | ||
193 | {0x3621, 0xaf}, | ||
194 | |||
195 | {0x3632, 0x5a}, | ||
196 | {0x3703, 0xb0}, | ||
197 | {0x370c, 0xc5}, | ||
198 | {0x370d, 0x42}, | ||
199 | {0x3713, 0x2f}, | ||
200 | {0x3800, 0x03}, | ||
201 | {0x3801, 0x3c}, | ||
202 | {0x3802, 0x00}, | ||
203 | {0x3803, 0x06}, | ||
204 | {0x3804, 0x05}, | ||
205 | {0x3805, 0x10}, | ||
206 | {0x3806, 0x03}, | ||
207 | {0x3807, 0xd0}, | ||
208 | {0x3808, 0x05}, | ||
209 | |||
210 | {0x3809, 0x10}, | ||
211 | |||
212 | {0x380a, 0x03}, | ||
213 | |||
214 | {0x380b, 0xd0}, | ||
215 | |||
216 | {0x380c, 0x08}, | ||
217 | |||
218 | {0x380d, 0xa8}, | ||
219 | |||
220 | {0x380e, 0x05}, | ||
221 | |||
222 | {0x380f, 0xa4}, | ||
223 | |||
224 | {0x3818, 0xc1}, | ||
225 | {0x381a, 0x00}, | ||
226 | {0x3a0d, 0x08}, | ||
227 | {0x3c01, 0x00}, | ||
228 | {0x3007, 0x3b}, | ||
229 | {0x5059, 0x80}, | ||
230 | {0x3003, 0x03}, | ||
231 | {0x3500, 0x00}, | ||
232 | |||
233 | {0x3501, 0x5a}, | ||
234 | {0x3502, 0x10}, | ||
235 | {0x350a, 0x00}, | ||
236 | {0x350b, 0x10}, | ||
237 | {0x401d, 0x08}, | ||
238 | {0x4801, 0x0f}, | ||
239 | {0x300e, 0x0c}, | ||
240 | {0x4803, 0x50}, | ||
241 | {0x4800, 0x34}, | ||
242 | {OV5650_TABLE_END, 0x0000} | ||
243 | }; | ||
244 | |||
245 | static struct ov5650_reg mode_2080x1164[] = { | ||
246 | {0x3103, 0x93}, | ||
247 | {0x3007, 0x3b}, | ||
248 | {0x3017, 0xff}, | ||
249 | {0x3018, 0xfc}, | ||
250 | |||
251 | {0x3600, 0x54}, | ||
252 | {0x3601, 0x05}, | ||
253 | {0x3603, 0xa7}, | ||
254 | {0x3604, 0x40}, | ||
255 | {0x3605, 0x04}, | ||
256 | {0x3606, 0x3f}, | ||
257 | {0x3612, 0x1a}, | ||
258 | {0x3613, 0x44}, | ||
259 | {0x3615, 0x52}, | ||
260 | {0x3620, 0x56}, | ||
261 | {0x3623, 0x01}, | ||
262 | {0x3630, 0x22}, | ||
263 | {0x3631, 0x36}, | ||
264 | {0x3632, 0x5f}, | ||
265 | {0x3633, 0x24}, | ||
266 | |||
267 | {0x3702, 0x3a}, | ||
268 | {0x3704, 0x18}, | ||
269 | {0x3706, 0x41}, | ||
270 | {0x370b, 0x40}, | ||
271 | {0x370e, 0x00}, | ||
272 | {0x3710, 0x28}, | ||
273 | {0x3711, 0x24}, | ||
274 | {0x3712, 0x13}, | ||
275 | |||
276 | {0x3810, 0x00}, | ||
277 | {0x3815, 0x82}, | ||
278 | {0x3830, 0x50}, | ||
279 | {0x3836, 0x00}, | ||
280 | |||
281 | {0x3a1a, 0x06}, | ||
282 | {0x3a18, 0x00}, | ||
283 | {0x3a19, 0xf8}, | ||
284 | {0x3a00, 0x38}, | ||
285 | |||
286 | {0x3a0d, 0x06}, | ||
287 | {0x3c01, 0x34}, | ||
288 | |||
289 | {0x401f, 0x03}, | ||
290 | {0x4000, 0x05}, | ||
291 | {0x401d, 0x08}, | ||
292 | {0x4001, 0x02}, | ||
293 | |||
294 | {0x5000, 0x00}, | ||
295 | {0x5001, 0x00}, | ||
296 | {0x5002, 0x00}, | ||
297 | {0x503d, 0x00}, | ||
298 | {0x5046, 0x00}, | ||
299 | |||
300 | {0x300f, 0x8f}, | ||
301 | |||
302 | {0x3010, 0x10}, | ||
303 | {0x3011, 0x14}, | ||
304 | {0x3012, 0x02}, | ||
305 | {0x3503, 0x33}, | ||
306 | |||
307 | |||
308 | {0x3621, 0x2f}, | ||
309 | |||
310 | {0x3703, 0xe6}, | ||
311 | {0x370c, 0x00}, | ||
312 | {0x370d, 0x04}, | ||
313 | {0x3713, 0x22}, | ||
314 | {0x3714, 0x27}, | ||
315 | {0x3705, 0xda}, | ||
316 | {0x370a, 0x80}, | ||
317 | |||
318 | {0x3800, 0x02}, | ||
319 | {0x3801, 0x12}, | ||
320 | {0x3802, 0x00}, | ||
321 | {0x3803, 0x0a}, | ||
322 | {0x3804, 0x08}, | ||
323 | {0x3805, 0x20}, | ||
324 | {0x3806, 0x04}, | ||
325 | {0x3807, 0x92}, | ||
326 | {0x3808, 0x08}, | ||
327 | |||
328 | {0x3809, 0x20}, | ||
329 | |||
330 | {0x380a, 0x04}, | ||
331 | |||
332 | {0x380b, 0x92}, | ||
333 | |||
334 | {0x380c, 0x0a}, | ||
335 | |||
336 | {0x380d, 0x96}, | ||
337 | |||
338 | {0x380e, 0x04}, | ||
339 | |||
340 | {0x380f, 0x9e}, | ||
341 | |||
342 | {0x3818, 0xc0}, | ||
343 | {0x381a, 0x3c}, | ||
344 | {0x381c, 0x31}, | ||
345 | {0x381d, 0x8e}, | ||
346 | {0x381e, 0x04}, | ||
347 | {0x381f, 0x92}, | ||
348 | {0x3820, 0x04}, | ||
349 | {0x3821, 0x19}, | ||
350 | {0x3824, 0x01}, | ||
351 | {0x3827, 0x0a}, | ||
352 | {0x401c, 0x46}, | ||
353 | |||
354 | {0x3003, 0x03}, | ||
355 | {0x3500, 0x00}, | ||
356 | {0x3501, 0x49}, | ||
357 | {0x3502, 0xa0}, | ||
358 | {0x350a, 0x00}, | ||
359 | {0x350b, 0x00}, | ||
360 | {0x4801, 0x0f}, | ||
361 | {0x300e, 0x0c}, | ||
362 | {0x4803, 0x50}, | ||
363 | {0x4800, 0x34}, | ||
364 | |||
365 | {OV5650_TABLE_END, 0x0000} | ||
366 | }; | ||
367 | |||
368 | static struct ov5650_reg mode_1920x1080[] = { | ||
369 | {0x3103, 0x93}, | ||
370 | {0x3007, 0x3b}, | ||
371 | {0x3017, 0xff}, | ||
372 | {0x3018, 0xfc}, | ||
373 | |||
374 | {0x3600, 0x54}, | ||
375 | {0x3601, 0x05}, | ||
376 | {0x3603, 0xa7}, | ||
377 | {0x3604, 0x40}, | ||
378 | {0x3605, 0x04}, | ||
379 | {0x3606, 0x3f}, | ||
380 | {0x3612, 0x1a}, | ||
381 | {0x3613, 0x44}, | ||
382 | {0x3615, 0x52}, | ||
383 | {0x3620, 0x56}, | ||
384 | {0x3623, 0x01}, | ||
385 | {0x3630, 0x22}, | ||
386 | {0x3631, 0x36}, | ||
387 | {0x3632, 0x5f}, | ||
388 | {0x3633, 0x24}, | ||
389 | |||
390 | {0x3702, 0x3a}, | ||
391 | {0x3704, 0x18}, | ||
392 | {0x3706, 0x41}, | ||
393 | {0x370b, 0x40}, | ||
394 | {0x370e, 0x00}, | ||
395 | {0x3710, 0x28}, | ||
396 | {0x3711, 0x24}, | ||
397 | {0x3712, 0x13}, | ||
398 | |||
399 | {0x3810, 0x00}, | ||
400 | {0x3815, 0x82}, | ||
401 | |||
402 | {0x3830, 0x50}, | ||
403 | {0x3836, 0x00}, | ||
404 | |||
405 | {0x3a1a, 0x06}, | ||
406 | {0x3a18, 0x00}, | ||
407 | {0x3a19, 0xf8}, | ||
408 | {0x3a00, 0x38}, | ||
409 | {0x3a0d, 0x06}, | ||
410 | {0x3c01, 0x34}, | ||
411 | |||
412 | {0x401f, 0x03}, | ||
413 | {0x4000, 0x05}, | ||
414 | {0x401d, 0x08}, | ||
415 | {0x4001, 0x02}, | ||
416 | |||
417 | {0x5000, 0x00}, | ||
418 | {0x5001, 0x00}, | ||
419 | {0x5002, 0x00}, | ||
420 | {0x503d, 0x00}, | ||
421 | {0x5046, 0x00}, | ||
422 | |||
423 | {0x300f, 0x8f}, | ||
424 | {0x3010, 0x10}, | ||
425 | {0x3011, 0x14}, | ||
426 | {0x3012, 0x02}, | ||
427 | {0x3503, 0x33}, | ||
428 | |||
429 | {0x3621, 0x2f}, | ||
430 | {0x3703, 0xe6}, | ||
431 | {0x370c, 0x00}, | ||
432 | {0x370d, 0x04}, | ||
433 | {0x3713, 0x22}, | ||
434 | {0x3714, 0x27}, | ||
435 | {0x3705, 0xda}, | ||
436 | {0x370a, 0x80}, | ||
437 | |||
438 | {0x3800, 0x02}, | ||
439 | {0x3801, 0x94}, | ||
440 | {0x3802, 0x00}, | ||
441 | {0x3803, 0x0c}, | ||
442 | {0x3804, 0x07}, | ||
443 | {0x3805, 0x80}, | ||
444 | {0x3806, 0x04}, | ||
445 | {0x3807, 0x40}, | ||
446 | {0x3808, 0x07}, | ||
447 | {0x3809, 0x80}, | ||
448 | {0x380a, 0x04}, | ||
449 | {0x380b, 0x40}, | ||
450 | {0x380c, 0x0a}, | ||
451 | {0x380d, 0x84}, | ||
452 | {0x380e, 0x04}, | ||
453 | {0x380f, 0xa4}, | ||
454 | {0x3818, 0xc0}, | ||
455 | {0x381a, 0x3c}, | ||
456 | {0x381c, 0x31}, | ||
457 | {0x381d, 0xa4}, | ||
458 | {0x381e, 0x04}, | ||
459 | {0x381f, 0x60}, | ||
460 | {0x3820, 0x03}, | ||
461 | {0x3821, 0x1a}, | ||
462 | {0x3824, 0x01}, | ||
463 | {0x3827, 0x0a}, | ||
464 | {0x401c, 0x46}, | ||
465 | |||
466 | {0x3003, 0x03}, | ||
467 | {0x3500, 0x00}, | ||
468 | {0x3501, 0x49}, | ||
469 | {0x3502, 0xa0}, | ||
470 | {0x350a, 0x00}, | ||
471 | {0x350b, 0x00}, | ||
472 | {0x4801, 0x0f}, | ||
473 | {0x300e, 0x0c}, | ||
474 | {0x4803, 0x50}, | ||
475 | {0x4800, 0x34}, | ||
476 | |||
477 | {OV5650_TABLE_END, 0x0000} | ||
478 | }; | ||
479 | |||
480 | |||
481 | static struct ov5650_reg mode_1264x704[] = { | ||
482 | {0x3600, 0x54}, | ||
483 | {0x3601, 0x05}, | ||
484 | {0x3604, 0x40}, | ||
485 | {0x3705, 0xdb}, | ||
486 | {0x370a, 0x81}, | ||
487 | {0x3615, 0x52}, | ||
488 | {0x3810, 0x40}, | ||
489 | {0x3836, 0x41}, | ||
490 | {0x4000, 0x05}, | ||
491 | {0x401c, 0x42}, | ||
492 | {0x401d, 0x08}, | ||
493 | {0x5046, 0x09}, | ||
494 | {0x3010, 0x00}, | ||
495 | {0x3503, 0x00}, | ||
496 | {0x3613, 0xc4}, | ||
497 | |||
498 | {0x3621, 0xaf}, | ||
499 | |||
500 | {0x3632, 0x55}, | ||
501 | {0x3703, 0x9a}, | ||
502 | {0x370c, 0x00}, | ||
503 | {0x370d, 0x42}, | ||
504 | {0x3713, 0x22}, | ||
505 | {0x3800, 0x02}, | ||
506 | {0x3801, 0x54}, | ||
507 | {0x3802, 0x00}, | ||
508 | {0x3803, 0x0c}, | ||
509 | {0x3804, 0x05}, | ||
510 | {0x3805, 0x00}, | ||
511 | {0x3806, 0x02}, | ||
512 | {0x3807, 0xd0}, | ||
513 | {0x3808, 0x05}, | ||
514 | |||
515 | {0x3809, 0x00}, | ||
516 | |||
517 | {0x380a, 0x02}, | ||
518 | |||
519 | {0x380b, 0xd0}, | ||
520 | |||
521 | {0x380c, 0x08}, | ||
522 | |||
523 | {0x380d, 0x72}, | ||
524 | |||
525 | {0x380e, 0x02}, | ||
526 | |||
527 | {0x380f, 0xe4}, | ||
528 | |||
529 | {0x3818, 0xc1}, | ||
530 | {0x381a, 0x3c}, | ||
531 | {0x3a0d, 0x06}, | ||
532 | {0x3c01, 0x34}, | ||
533 | {0x3007, 0x3b}, | ||
534 | {0x5059, 0x80}, | ||
535 | {0x3003, 0x03}, | ||
536 | {0x3500, 0x04}, | ||
537 | {0x3501, 0xa5}, | ||
538 | |||
539 | {0x3502, 0x10}, | ||
540 | |||
541 | {0x350a, 0x00}, | ||
542 | {0x350b, 0x00}, | ||
543 | {0x4801, 0x0f}, | ||
544 | {0x300e, 0x0c}, | ||
545 | {0x4803, 0x50}, | ||
546 | {0x4800, 0x24}, | ||
547 | {0x300f, 0x8b}, | ||
548 | |||
549 | {0x3711, 0x24}, | ||
550 | {0x3713, 0x92}, | ||
551 | {0x3714, 0x17}, | ||
552 | {0x381c, 0x10}, | ||
553 | {0x381d, 0x82}, | ||
554 | {0x381e, 0x05}, | ||
555 | {0x381f, 0xc0}, | ||
556 | {0x3821, 0x20}, | ||
557 | {0x3824, 0x23}, | ||
558 | {0x3825, 0x2c}, | ||
559 | {0x3826, 0x00}, | ||
560 | {0x3827, 0x0c}, | ||
561 | {0x3623, 0x01}, | ||
562 | {0x3633, 0x24}, | ||
563 | {0x3632, 0x5f}, | ||
564 | {0x401f, 0x03}, | ||
565 | |||
566 | {OV5650_TABLE_END, 0x0000} | ||
567 | }; | ||
568 | |||
569 | static struct ov5650_reg mode_320x240[] = { | ||
570 | {0x3103, 0x93}, | ||
571 | {0x3b07, 0x0c}, | ||
572 | {0x3017, 0xff}, | ||
573 | {0x3018, 0xfc}, | ||
574 | {0x3706, 0x41}, | ||
575 | {0x3613, 0xc4}, | ||
576 | {0x370d, 0x42}, | ||
577 | {0x3703, 0x9a}, | ||
578 | {0x3630, 0x22}, | ||
579 | {0x3605, 0x04}, | ||
580 | {0x3606, 0x3f}, | ||
581 | {0x3712, 0x13}, | ||
582 | {0x370e, 0x00}, | ||
583 | {0x370b, 0x40}, | ||
584 | {0x3600, 0x54}, | ||
585 | {0x3601, 0x05}, | ||
586 | {0x3713, 0x22}, | ||
587 | {0x3714, 0x27}, | ||
588 | {0x3631, 0x22}, | ||
589 | {0x3612, 0x1a}, | ||
590 | {0x3604, 0x40}, | ||
591 | {0x3705, 0xdc}, | ||
592 | {0x370a, 0x83}, | ||
593 | {0x370c, 0xc8}, | ||
594 | {0x3710, 0x28}, | ||
595 | {0x3702, 0x3a}, | ||
596 | {0x3704, 0x18}, | ||
597 | {0x3a18, 0x00}, | ||
598 | {0x3a19, 0xf8}, | ||
599 | {0x3a00, 0x38}, | ||
600 | {0x3800, 0x02}, | ||
601 | {0x3801, 0x54}, | ||
602 | {0x3803, 0x0c}, | ||
603 | {0x380c, 0x0c}, | ||
604 | {0x380d, 0xb4}, | ||
605 | {0x380e, 0x07}, | ||
606 | {0x380f, 0xb0}, | ||
607 | {0x3830, 0x50}, | ||
608 | {0x3a08, 0x12}, | ||
609 | {0x3a09, 0x70}, | ||
610 | {0x3a0a, 0x0f}, | ||
611 | {0x3a0b, 0x60}, | ||
612 | {0x3a0d, 0x06}, | ||
613 | {0x3a0e, 0x06}, | ||
614 | {0x3a13, 0x54}, | ||
615 | {0x3815, 0x82}, | ||
616 | {0x5059, 0x80}, | ||
617 | {0x3615, 0x52}, | ||
618 | {0x505a, 0x0a}, | ||
619 | {0x505b, 0x2e}, | ||
620 | {0x3713, 0x92}, | ||
621 | {0x3714, 0x17}, | ||
622 | {0x3803, 0x0a}, | ||
623 | {0x3804, 0x05}, | ||
624 | {0x3805, 0x00}, | ||
625 | {0x3806, 0x01}, | ||
626 | {0x3807, 0x00}, | ||
627 | {0x3808, 0x01}, | ||
628 | {0x3809, 0x40}, | ||
629 | {0x380a, 0x01}, | ||
630 | {0x380b, 0x00}, | ||
631 | {0x380c, 0x0a}, | ||
632 | |||
633 | {0x380d, 0x04}, | ||
634 | |||
635 | {0x380e, 0x01}, | ||
636 | |||
637 | {0x380f, 0x38}, | ||
638 | |||
639 | {0x3815, 0x81}, | ||
640 | {0x3824, 0x23}, | ||
641 | {0x3825, 0x20}, | ||
642 | {0x3826, 0x00}, | ||
643 | {0x3827, 0x08}, | ||
644 | {0x370d, 0xc2}, | ||
645 | {0x3a08, 0x17}, | ||
646 | {0x3a09, 0x64}, | ||
647 | {0x3a0a, 0x13}, | ||
648 | {0x3a0b, 0x80}, | ||
649 | {0x3a00, 0x58}, | ||
650 | {0x3a1a, 0x06}, | ||
651 | {0x3503, 0x33}, | ||
652 | {0x3623, 0x01}, | ||
653 | {0x3633, 0x24}, | ||
654 | {0x3c01, 0x34}, | ||
655 | {0x3c04, 0x28}, | ||
656 | {0x3c05, 0x98}, | ||
657 | {0x3c07, 0x07}, | ||
658 | {0x3c09, 0xc2}, | ||
659 | {0x4000, 0x05}, | ||
660 | {0x401d, 0x08}, | ||
661 | {0x4001, 0x02}, | ||
662 | {0x401c, 0x42}, | ||
663 | {0x5046, 0x09}, | ||
664 | {0x3810, 0x40}, | ||
665 | {0x3836, 0x41}, | ||
666 | {0x505f, 0x04}, | ||
667 | {0x5000, 0x06}, | ||
668 | {0x5001, 0x00}, | ||
669 | {0x5002, 0x02}, | ||
670 | {0x503d, 0x00}, | ||
671 | {0x5901, 0x08}, | ||
672 | {0x585a, 0x01}, | ||
673 | {0x585b, 0x2c}, | ||
674 | {0x585c, 0x01}, | ||
675 | {0x585d, 0x93}, | ||
676 | {0x585e, 0x01}, | ||
677 | {0x585f, 0x90}, | ||
678 | {0x5860, 0x01}, | ||
679 | {0x5861, 0x0d}, | ||
680 | {0x5180, 0xc0}, | ||
681 | {0x5184, 0x00}, | ||
682 | {0x470a, 0x00}, | ||
683 | {0x470b, 0x00}, | ||
684 | {0x470c, 0x00}, | ||
685 | {0x300f, 0x8e}, | ||
686 | {0x3603, 0xa7}, | ||
687 | {0x3632, 0x55}, | ||
688 | {0x3620, 0x56}, | ||
689 | {0x3621, 0xaf}, | ||
690 | {0x3818, 0xc3}, | ||
691 | {0x3631, 0x36}, | ||
692 | {0x3632, 0x5f}, | ||
693 | {0x3711, 0x24}, | ||
694 | {0x401f, 0x03}, | ||
695 | |||
696 | {0x3011, 0x14}, | ||
697 | {0x3007, 0x3B}, | ||
698 | {0x300f, 0x8f}, | ||
699 | {0x4801, 0x0f}, | ||
700 | {0x3003, 0x03}, | ||
701 | {0x300e, 0x0c}, | ||
702 | {0x3010, 0x15}, | ||
703 | {0x4803, 0x50}, | ||
704 | {0x4800, 0x24}, | ||
705 | {0x4837, 0x40}, | ||
706 | {0x3815, 0x82}, | ||
707 | |||
708 | {OV5650_TABLE_END, 0x0000} | ||
709 | }; | ||
710 | |||
711 | static struct ov5650_reg mode_end[] = { | ||
712 | {0x3212, 0x00}, | ||
713 | {0x3003, 0x01}, | ||
714 | {0x3212, 0x10}, | ||
715 | {0x3212, 0xa0}, | ||
716 | {0x3008, 0x02}, | ||
717 | |||
718 | {OV5650_TABLE_END, 0x0000} | ||
719 | }; | ||
720 | |||
721 | enum { | ||
722 | OV5650_MODE_2592x1944, | ||
723 | OV5650_MODE_1296x972, | ||
724 | OV5650_MODE_2080x1164, | ||
725 | OV5650_MODE_1920x1080, | ||
726 | OV5650_MODE_1264x704, | ||
727 | OV5650_MODE_320x240, | ||
728 | OV5650_MODE_INVALID | ||
729 | }; | ||
730 | |||
731 | static struct ov5650_reg *mode_table[] = { | ||
732 | [OV5650_MODE_2592x1944] = mode_2592x1944, | ||
733 | [OV5650_MODE_1296x972] = mode_1296x972, | ||
734 | [OV5650_MODE_2080x1164] = mode_2080x1164, | ||
735 | [OV5650_MODE_1920x1080] = mode_1920x1080, | ||
736 | [OV5650_MODE_1264x704] = mode_1264x704, | ||
737 | [OV5650_MODE_320x240] = mode_320x240 | ||
738 | }; | ||
739 | |||
740 | static inline void ov5650_get_frame_length_regs(struct ov5650_reg *regs, | ||
741 | u32 frame_length) | ||
742 | { | ||
743 | regs->addr = 0x380e; | ||
744 | regs->val = (frame_length >> 8) & 0xff; | ||
745 | (regs + 1)->addr = 0x380f; | ||
746 | (regs + 1)->val = (frame_length) & 0xff; | ||
747 | } | ||
748 | |||
749 | static inline void ov5650_get_coarse_time_regs(struct ov5650_reg *regs, | ||
750 | u32 coarse_time) | ||
751 | { | ||
752 | regs->addr = 0x3500; | ||
753 | regs->val = (coarse_time >> 12) & 0xff; | ||
754 | (regs + 1)->addr = 0x3501; | ||
755 | (regs + 1)->val = (coarse_time >> 4) & 0xff; | ||
756 | (regs + 2)->addr = 0x3502; | ||
757 | (regs + 2)->val = (coarse_time & 0xf) << 4; | ||
758 | } | ||
759 | |||
760 | static inline void ov5650_get_gain_reg(struct ov5650_reg *regs, u16 gain) | ||
761 | { | ||
762 | regs->addr = 0x350b; | ||
763 | regs->val = gain; | ||
764 | } | ||
765 | |||
766 | static int ov5650_read_reg(struct i2c_client *client, u16 addr, u8 *val) | ||
767 | { | ||
768 | int err; | ||
769 | struct i2c_msg msg[2]; | ||
770 | unsigned char data[3]; | ||
771 | |||
772 | if (!client->adapter) | ||
773 | return -ENODEV; | ||
774 | |||
775 | msg[0].addr = client->addr; | ||
776 | msg[0].flags = 0; | ||
777 | msg[0].len = 2; | ||
778 | msg[0].buf = data; | ||
779 | |||
780 | /* high byte goes out first */ | ||
781 | data[0] = (u8) (addr >> 8); | ||
782 | data[1] = (u8) (addr & 0xff); | ||
783 | |||
784 | msg[1].addr = client->addr; | ||
785 | msg[1].flags = I2C_M_RD; | ||
786 | msg[1].len = 1; | ||
787 | msg[1].buf = data + 2; | ||
788 | |||
789 | err = i2c_transfer(client->adapter, msg, 2); | ||
790 | |||
791 | if (err != 1) | ||
792 | return -EINVAL; | ||
793 | |||
794 | *val = data[2]; | ||
795 | |||
796 | return 0; | ||
797 | } | ||
798 | |||
799 | static int ov5650_read_reg_helper(struct ov5650_info *info, | ||
800 | u16 addr, u8 *val) | ||
801 | { | ||
802 | int ret; | ||
803 | switch (info->camera_mode) { | ||
804 | case Main: | ||
805 | case StereoCameraMode_Left: | ||
806 | ret = ov5650_read_reg(info->left.i2c_client, addr, val); | ||
807 | break; | ||
808 | case StereoCameraMode_Stereo: | ||
809 | ret = ov5650_read_reg(info->left.i2c_client, addr, val); | ||
810 | if (ret) | ||
811 | break; | ||
812 | ret = ov5650_read_reg(info->right.i2c_client, addr, val); | ||
813 | break; | ||
814 | case StereoCameraMode_Right: | ||
815 | ret = ov5650_read_reg(info->right.i2c_client, addr, val); | ||
816 | break; | ||
817 | default: | ||
818 | return -1; | ||
819 | } | ||
820 | return ret; | ||
821 | } | ||
822 | |||
823 | static int ov5650_write_reg(struct i2c_client *client, u16 addr, u8 val) | ||
824 | { | ||
825 | int err; | ||
826 | struct i2c_msg msg; | ||
827 | unsigned char data[3]; | ||
828 | |||
829 | if (!client->adapter) | ||
830 | return -ENODEV; | ||
831 | |||
832 | data[0] = (u8) (addr >> 8); | ||
833 | data[1] = (u8) (addr & 0xff); | ||
834 | data[2] = (u8) (val & 0xff); | ||
835 | |||
836 | msg.addr = client->addr; | ||
837 | msg.flags = 0; | ||
838 | msg.len = 3; | ||
839 | msg.buf = data; | ||
840 | |||
841 | err = i2c_transfer(client->adapter, &msg, 1); | ||
842 | if (err == 1) | ||
843 | return 0; | ||
844 | |||
845 | pr_err("ov5650: i2c transfer failed, retrying %x %x\n", addr, val); | ||
846 | |||
847 | return err; | ||
848 | } | ||
849 | |||
850 | static int ov5650_write_reg_helper(struct ov5650_info *info, | ||
851 | u16 addr, u8 val) | ||
852 | { | ||
853 | int ret; | ||
854 | switch (info->camera_mode) { | ||
855 | case Main: | ||
856 | case StereoCameraMode_Left: | ||
857 | ret = ov5650_write_reg(info->left.i2c_client, addr, val); | ||
858 | break; | ||
859 | case StereoCameraMode_Stereo: | ||
860 | ret = ov5650_write_reg(info->left.i2c_client, addr, val); | ||
861 | if (ret) | ||
862 | break; | ||
863 | ret = ov5650_write_reg(info->right.i2c_client, addr, val); | ||
864 | break; | ||
865 | case StereoCameraMode_Right: | ||
866 | ret = ov5650_write_reg(info->right.i2c_client, addr, val); | ||
867 | break; | ||
868 | default: | ||
869 | return -1; | ||
870 | } | ||
871 | return ret; | ||
872 | } | ||
873 | |||
874 | static int ov5650_write_bulk_reg(struct i2c_client *client, u8 *data, int len) | ||
875 | { | ||
876 | int err; | ||
877 | struct i2c_msg msg; | ||
878 | |||
879 | if (!client->adapter) | ||
880 | return -ENODEV; | ||
881 | |||
882 | msg.addr = client->addr; | ||
883 | msg.flags = 0; | ||
884 | msg.len = len; | ||
885 | msg.buf = data; | ||
886 | |||
887 | err = i2c_transfer(client->adapter, &msg, 1); | ||
888 | if (err == 1) | ||
889 | return 0; | ||
890 | |||
891 | pr_err("ov5650: i2c bulk transfer failed at %x\n", | ||
892 | (int)data[0] << 8 | data[1]); | ||
893 | |||
894 | return err; | ||
895 | } | ||
896 | |||
897 | static int ov5650_write_bulk_reg_helper(struct ov5650_info *info, int len) | ||
898 | { | ||
899 | int ret; | ||
900 | switch (info->camera_mode) { | ||
901 | case Main: | ||
902 | case StereoCameraMode_Left: | ||
903 | ret = ov5650_write_bulk_reg(info->left.i2c_client, | ||
904 | info->i2c_trans_buf, len); | ||
905 | break; | ||
906 | case StereoCameraMode_Stereo: | ||
907 | ret = ov5650_write_bulk_reg(info->left.i2c_client, | ||
908 | info->i2c_trans_buf, len); | ||
909 | if (ret) | ||
910 | break; | ||
911 | ret = ov5650_write_bulk_reg(info->right.i2c_client, | ||
912 | info->i2c_trans_buf, len); | ||
913 | break; | ||
914 | case StereoCameraMode_Right: | ||
915 | ret = ov5650_write_bulk_reg(info->right.i2c_client, | ||
916 | info->i2c_trans_buf, len); | ||
917 | break; | ||
918 | default: | ||
919 | return -1; | ||
920 | } | ||
921 | return ret; | ||
922 | } | ||
923 | |||
924 | static int ov5650_write_table(struct ov5650_info *info, | ||
925 | const struct ov5650_reg table[], | ||
926 | const struct ov5650_reg override_list[], | ||
927 | int num_override_regs) | ||
928 | { | ||
929 | int err; | ||
930 | const struct ov5650_reg *next, *n_next; | ||
931 | u8 *b_ptr = info->i2c_trans_buf; | ||
932 | unsigned int buf_filled = 0; | ||
933 | unsigned int i; | ||
934 | u16 val; | ||
935 | |||
936 | for (next = table; next->addr != OV5650_TABLE_END; next++) { | ||
937 | if (next->addr == OV5650_TABLE_WAIT_MS) { | ||
938 | msleep(next->val); | ||
939 | continue; | ||
940 | } | ||
941 | |||
942 | val = next->val; | ||
943 | /* When an override list is passed in, replace the reg */ | ||
944 | /* value to write if the reg is in the list */ | ||
945 | if (override_list) { | ||
946 | for (i = 0; i < num_override_regs; i++) { | ||
947 | if (next->addr == override_list[i].addr) { | ||
948 | val = override_list[i].val; | ||
949 | break; | ||
950 | } | ||
951 | } | ||
952 | } | ||
953 | |||
954 | if (!buf_filled) { | ||
955 | b_ptr = info->i2c_trans_buf; | ||
956 | *b_ptr++ = next->addr >> 8; | ||
957 | *b_ptr++ = next->addr & 0xff; | ||
958 | buf_filled = 2; | ||
959 | } | ||
960 | *b_ptr++ = val; | ||
961 | buf_filled++; | ||
962 | |||
963 | n_next = next + 1; | ||
964 | if (n_next->addr != OV5650_TABLE_END && | ||
965 | n_next->addr != OV5650_TABLE_WAIT_MS && | ||
966 | buf_filled < SIZEOF_I2C_TRANSBUF && | ||
967 | n_next->addr == next->addr + 1) { | ||
968 | continue; | ||
969 | } | ||
970 | |||
971 | err = ov5650_write_bulk_reg_helper(info, buf_filled); | ||
972 | if (err) | ||
973 | return err; | ||
974 | |||
975 | buf_filled = 0; | ||
976 | } | ||
977 | return 0; | ||
978 | } | ||
979 | |||
980 | static int ov5650_set_mode(struct ov5650_info *info, struct ov5650_mode *mode) | ||
981 | { | ||
982 | int sensor_mode; | ||
983 | int err; | ||
984 | struct ov5650_reg reg_list[6]; | ||
985 | |||
986 | pr_info("%s: xres %u yres %u framelength %u coarsetime %u gain %u\n", | ||
987 | __func__, mode->xres, mode->yres, mode->frame_length, | ||
988 | mode->coarse_time, mode->gain); | ||
989 | if (mode->xres == 2592 && mode->yres == 1944) | ||
990 | sensor_mode = OV5650_MODE_2592x1944; | ||
991 | else if (mode->xres == 1296 && mode->yres == 972) | ||
992 | sensor_mode = OV5650_MODE_1296x972; | ||
993 | else if (mode->xres == 2080 && mode->yres == 1164) | ||
994 | sensor_mode = OV5650_MODE_2080x1164; | ||
995 | else if (mode->xres == 1920 && mode->yres == 1080) | ||
996 | sensor_mode = OV5650_MODE_1920x1080; | ||
997 | else if (mode->xres == 1264 && mode->yres == 704) | ||
998 | sensor_mode = OV5650_MODE_1264x704; | ||
999 | else if (mode->xres == 320 && mode->yres == 240) | ||
1000 | sensor_mode = OV5650_MODE_320x240; | ||
1001 | else { | ||
1002 | pr_err("%s: invalid resolution supplied to set mode %d %d\n", | ||
1003 | __func__, mode->xres, mode->yres); | ||
1004 | return -EINVAL; | ||
1005 | } | ||
1006 | |||
1007 | /* get a list of override regs for the asking frame length, */ | ||
1008 | /* coarse integration time, and gain. */ | ||
1009 | ov5650_get_frame_length_regs(reg_list, mode->frame_length); | ||
1010 | ov5650_get_coarse_time_regs(reg_list + 2, mode->coarse_time); | ||
1011 | ov5650_get_gain_reg(reg_list + 5, mode->gain); | ||
1012 | |||
1013 | err = ov5650_write_table(info, reset_seq, NULL, 0); | ||
1014 | if (err) | ||
1015 | return err; | ||
1016 | |||
1017 | err = ov5650_write_table(info, mode_start, NULL, 0); | ||
1018 | if (err) | ||
1019 | return err; | ||
1020 | |||
1021 | err = ov5650_write_table(info, mode_table[sensor_mode], | ||
1022 | reg_list, 6); | ||
1023 | if (err) | ||
1024 | return err; | ||
1025 | |||
1026 | err = ov5650_write_table(info, mode_end, NULL, 0); | ||
1027 | if (err) | ||
1028 | return err; | ||
1029 | |||
1030 | info->mode = sensor_mode; | ||
1031 | return 0; | ||
1032 | } | ||
1033 | |||
1034 | static int ov5650_set_frame_length(struct ov5650_info *info, u32 frame_length) | ||
1035 | { | ||
1036 | int ret; | ||
1037 | struct ov5650_reg reg_list[2]; | ||
1038 | u8 *b_ptr = info->i2c_trans_buf; | ||
1039 | |||
1040 | ov5650_get_frame_length_regs(reg_list, frame_length); | ||
1041 | |||
1042 | *b_ptr++ = reg_list[0].addr >> 8; | ||
1043 | *b_ptr++ = reg_list[0].addr & 0xff; | ||
1044 | *b_ptr++ = reg_list[0].val & 0xff; | ||
1045 | *b_ptr++ = reg_list[1].val & 0xff; | ||
1046 | ret = ov5650_write_bulk_reg_helper(info, 4); | ||
1047 | |||
1048 | return ret; | ||
1049 | } | ||
1050 | |||
1051 | static int ov5650_set_coarse_time(struct ov5650_info *info, u32 coarse_time) | ||
1052 | { | ||
1053 | int ret; | ||
1054 | struct ov5650_reg reg_list[3]; | ||
1055 | u8 *b_ptr = info->i2c_trans_buf; | ||
1056 | |||
1057 | ov5650_get_coarse_time_regs(reg_list, coarse_time); | ||
1058 | |||
1059 | *b_ptr++ = reg_list[0].addr >> 8; | ||
1060 | *b_ptr++ = reg_list[0].addr & 0xff; | ||
1061 | *b_ptr++ = reg_list[0].val & 0xff; | ||
1062 | *b_ptr++ = reg_list[1].val & 0xff; | ||
1063 | *b_ptr++ = reg_list[2].val & 0xff; | ||
1064 | ret = ov5650_write_bulk_reg_helper(info, 5); | ||
1065 | |||
1066 | return ret; | ||
1067 | } | ||
1068 | |||
1069 | static int ov5650_set_gain(struct ov5650_info *info, u16 gain) | ||
1070 | { | ||
1071 | int ret; | ||
1072 | struct ov5650_reg reg_list; | ||
1073 | |||
1074 | ov5650_get_gain_reg(®_list, gain); | ||
1075 | ret = ov5650_write_reg_helper(info, reg_list.addr, reg_list.val); | ||
1076 | |||
1077 | return ret; | ||
1078 | } | ||
1079 | |||
1080 | static int ov5650_set_group_hold(struct ov5650_info *info, struct ov5650_ae *ae) | ||
1081 | { | ||
1082 | int ret; | ||
1083 | int count = 0; | ||
1084 | bool groupHoldEnabled = false; | ||
1085 | |||
1086 | if (ae->gain_enable) | ||
1087 | count++; | ||
1088 | if (ae->coarse_time_enable) | ||
1089 | count++; | ||
1090 | if (ae->frame_length_enable) | ||
1091 | count++; | ||
1092 | if (count >= 2) | ||
1093 | groupHoldEnabled = true; | ||
1094 | |||
1095 | if (groupHoldEnabled) { | ||
1096 | ret = ov5650_write_reg_helper(info, 0x3212, 0x01); | ||
1097 | if (ret) | ||
1098 | return ret; | ||
1099 | } | ||
1100 | |||
1101 | if (ae->gain_enable) | ||
1102 | ov5650_set_gain(info, ae->gain); | ||
1103 | if (ae->coarse_time_enable) | ||
1104 | ov5650_set_coarse_time(info, ae->coarse_time); | ||
1105 | if (ae->frame_length_enable) | ||
1106 | ov5650_set_frame_length(info, ae->frame_length); | ||
1107 | |||
1108 | if (groupHoldEnabled) { | ||
1109 | ret = ov5650_write_reg_helper(info, 0x3212, 0x11); | ||
1110 | if (ret) | ||
1111 | return ret; | ||
1112 | |||
1113 | ret = ov5650_write_reg_helper(info, 0x3212, 0xa1); | ||
1114 | if (ret) | ||
1115 | return ret; | ||
1116 | } | ||
1117 | |||
1118 | return 0; | ||
1119 | } | ||
1120 | |||
1121 | |||
1122 | static int ov5650_set_binning(struct ov5650_info *info, u8 enable) | ||
1123 | { | ||
1124 | s32 ret; | ||
1125 | u8 array_ctrl_reg, analog_ctrl_reg, timing_reg; | ||
1126 | u32 val; | ||
1127 | |||
1128 | if (info->mode == OV5650_MODE_2592x1944 | ||
1129 | || info->mode == OV5650_MODE_2080x1164 | ||
1130 | || info->mode >= OV5650_MODE_INVALID) { | ||
1131 | return -EINVAL; | ||
1132 | } | ||
1133 | |||
1134 | ov5650_read_reg_helper(info, OV5650_ARRAY_CONTROL_01, &array_ctrl_reg); | ||
1135 | ov5650_read_reg_helper(info, OV5650_ANALOG_CONTROL_D, &analog_ctrl_reg); | ||
1136 | ov5650_read_reg_helper(info, OV5650_TIMING_TC_REG_18, &timing_reg); | ||
1137 | |||
1138 | ret = ov5650_write_reg_helper(info, | ||
1139 | OV5650_SRM_GRUP_ACCESS, | ||
1140 | OV5650_GROUP_ID(3)); | ||
1141 | if (ret < 0) | ||
1142 | return -EIO; | ||
1143 | |||
1144 | if (!enable) { | ||
1145 | ret = ov5650_write_reg_helper(info, | ||
1146 | OV5650_ARRAY_CONTROL_01, | ||
1147 | array_ctrl_reg | | ||
1148 | (OV5650_H_BINNING_BIT | OV5650_H_SUBSAMPLING_BIT)); | ||
1149 | |||
1150 | if (ret < 0) | ||
1151 | goto exit; | ||
1152 | |||
1153 | ret = ov5650_write_reg_helper(info, | ||
1154 | OV5650_ANALOG_CONTROL_D, | ||
1155 | analog_ctrl_reg & ~OV5650_V_BINNING_BIT); | ||
1156 | |||
1157 | if (ret < 0) | ||
1158 | goto exit; | ||
1159 | |||
1160 | ret = ov5650_write_reg_helper(info, | ||
1161 | OV5650_TIMING_TC_REG_18, | ||
1162 | timing_reg | OV5650_V_SUBSAMPLING_BIT); | ||
1163 | |||
1164 | if (ret < 0) | ||
1165 | goto exit; | ||
1166 | |||
1167 | if (info->mode == OV5650_MODE_1296x972) | ||
1168 | val = 0x1A2; | ||
1169 | else | ||
1170 | /* FIXME: this value is not verified yet. */ | ||
1171 | val = 0x1A8; | ||
1172 | |||
1173 | ret = ov5650_write_reg_helper(info, | ||
1174 | OV5650_TIMING_CONTROL_HS_HIGH, | ||
1175 | (val >> 8)); | ||
1176 | |||
1177 | if (ret < 0) | ||
1178 | goto exit; | ||
1179 | |||
1180 | ret = ov5650_write_reg_helper(info, | ||
1181 | OV5650_TIMING_CONTROL_HS_LOW, | ||
1182 | (val & 0xFF)); | ||
1183 | } else { | ||
1184 | ret = ov5650_write_reg_helper(info, | ||
1185 | OV5650_ARRAY_CONTROL_01, | ||
1186 | (array_ctrl_reg | OV5650_H_BINNING_BIT) | ||
1187 | & ~OV5650_H_SUBSAMPLING_BIT); | ||
1188 | |||
1189 | if (ret < 0) | ||
1190 | goto exit; | ||
1191 | |||
1192 | ret = ov5650_write_reg_helper(info, | ||
1193 | OV5650_ANALOG_CONTROL_D, | ||
1194 | analog_ctrl_reg | OV5650_V_BINNING_BIT); | ||
1195 | |||
1196 | if (ret < 0) | ||
1197 | goto exit; | ||
1198 | |||
1199 | ret = ov5650_write_reg_helper(info, | ||
1200 | OV5650_TIMING_TC_REG_18, | ||
1201 | timing_reg | OV5650_V_SUBSAMPLING_BIT); | ||
1202 | |||
1203 | if (ret < 0) | ||
1204 | goto exit; | ||
1205 | |||
1206 | if (info->mode == OV5650_MODE_1296x972) | ||
1207 | val = 0x33C; | ||
1208 | else | ||
1209 | val = 0x254; | ||
1210 | |||
1211 | ret = ov5650_write_reg_helper(info, | ||
1212 | OV5650_TIMING_CONTROL_HS_HIGH, | ||
1213 | (val >> 8)); | ||
1214 | |||
1215 | if (ret < 0) | ||
1216 | goto exit; | ||
1217 | |||
1218 | ret = ov5650_write_reg_helper(info, | ||
1219 | OV5650_TIMING_CONTROL_HS_LOW, | ||
1220 | (val & 0xFF)); | ||
1221 | } | ||
1222 | |||
1223 | exit: | ||
1224 | ret = ov5650_write_reg_helper(info, | ||
1225 | OV5650_SRM_GRUP_ACCESS, | ||
1226 | (OV5650_GROUP_HOLD_END_BIT | OV5650_GROUP_ID(3))); | ||
1227 | |||
1228 | ret |= ov5650_write_reg_helper(info, | ||
1229 | OV5650_SRM_GRUP_ACCESS, | ||
1230 | (OV5650_GROUP_HOLD_BIT | OV5650_GROUP_LAUNCH_BIT | | ||
1231 | OV5650_GROUP_ID(3))); | ||
1232 | |||
1233 | return ret; | ||
1234 | } | ||
1235 | |||
1236 | static int ov5650_test_pattern(struct ov5650_info *info, | ||
1237 | enum ov5650_test_pattern pattern) | ||
1238 | { | ||
1239 | if (pattern >= ARRAY_SIZE(test_pattern_modes)) | ||
1240 | return -EINVAL; | ||
1241 | |||
1242 | return ov5650_write_table(info, | ||
1243 | test_pattern_modes[pattern], | ||
1244 | NULL, 0); | ||
1245 | } | ||
1246 | |||
1247 | static int set_power_helper(struct ov5650_platform_data *pdata, | ||
1248 | int powerLevel) | ||
1249 | { | ||
1250 | if (pdata) { | ||
1251 | if (powerLevel && pdata->power_on) | ||
1252 | pdata->power_on(); | ||
1253 | else if (pdata->power_off) | ||
1254 | pdata->power_off(); | ||
1255 | } | ||
1256 | return 0; | ||
1257 | } | ||
1258 | |||
1259 | static int ov5650_set_power(int powerLevel) | ||
1260 | { | ||
1261 | pr_info("%s: powerLevel=%d camera mode=%d\n", __func__, powerLevel, | ||
1262 | stereo_ov5650_info->camera_mode); | ||
1263 | |||
1264 | if (StereoCameraMode_Left & stereo_ov5650_info->camera_mode) | ||
1265 | set_power_helper(stereo_ov5650_info->left.pdata, powerLevel); | ||
1266 | |||
1267 | if (StereoCameraMode_Right & stereo_ov5650_info->camera_mode) | ||
1268 | set_power_helper(stereo_ov5650_info->right.pdata, powerLevel); | ||
1269 | |||
1270 | return 0; | ||
1271 | } | ||
1272 | |||
1273 | static long ov5650_ioctl(struct file *file, | ||
1274 | unsigned int cmd, unsigned long arg) | ||
1275 | { | ||
1276 | int err; | ||
1277 | struct ov5650_info *info = file->private_data; | ||
1278 | |||
1279 | switch (cmd) { | ||
1280 | case OV5650_IOCTL_SET_CAMERA_MODE: | ||
1281 | { | ||
1282 | if (info->camera_mode != arg) { | ||
1283 | err = ov5650_set_power(0); | ||
1284 | if (err) { | ||
1285 | pr_info("%s %d\n", __func__, __LINE__); | ||
1286 | return err; | ||
1287 | } | ||
1288 | info->camera_mode = arg; | ||
1289 | err = ov5650_set_power(1); | ||
1290 | if (err) | ||
1291 | return err; | ||
1292 | } | ||
1293 | return 0; | ||
1294 | } | ||
1295 | case OV5650_IOCTL_SYNC_SENSORS: | ||
1296 | if (info->right.pdata->synchronize_sensors) | ||
1297 | info->right.pdata->synchronize_sensors(); | ||
1298 | return 0; | ||
1299 | case OV5650_IOCTL_SET_MODE: | ||
1300 | { | ||
1301 | struct ov5650_mode mode; | ||
1302 | if (copy_from_user(&mode, | ||
1303 | (const void __user *)arg, | ||
1304 | sizeof(struct ov5650_mode))) { | ||
1305 | pr_info("%s %d\n", __func__, __LINE__); | ||
1306 | return -EFAULT; | ||
1307 | } | ||
1308 | |||
1309 | return ov5650_set_mode(info, &mode); | ||
1310 | } | ||
1311 | case OV5650_IOCTL_SET_FRAME_LENGTH: | ||
1312 | return ov5650_set_frame_length(info, (u32)arg); | ||
1313 | case OV5650_IOCTL_SET_COARSE_TIME: | ||
1314 | return ov5650_set_coarse_time(info, (u32)arg); | ||
1315 | case OV5650_IOCTL_SET_GAIN: | ||
1316 | return ov5650_set_gain(info, (u16)arg); | ||
1317 | case OV5650_IOCTL_SET_BINNING: | ||
1318 | return ov5650_set_binning(info, (u8)arg); | ||
1319 | case OV5650_IOCTL_GET_STATUS: | ||
1320 | { | ||
1321 | u16 status = 0; | ||
1322 | if (copy_to_user((void __user *)arg, &status, | ||
1323 | 2)) { | ||
1324 | pr_info("%s %d\n", __func__, __LINE__); | ||
1325 | return -EFAULT; | ||
1326 | } | ||
1327 | return 0; | ||
1328 | } | ||
1329 | case OV5650_IOCTL_TEST_PATTERN: | ||
1330 | { | ||
1331 | err = ov5650_test_pattern(info, (enum ov5650_test_pattern) arg); | ||
1332 | if (err) | ||
1333 | pr_err("%s %d %d\n", __func__, __LINE__, err); | ||
1334 | return err; | ||
1335 | } | ||
1336 | case OV5650_IOCTL_SET_GROUP_HOLD: | ||
1337 | { | ||
1338 | struct ov5650_ae ae; | ||
1339 | if (copy_from_user(&ae, | ||
1340 | (const void __user *)arg, | ||
1341 | sizeof(struct ov5650_ae))) { | ||
1342 | pr_info("%s %d\n", __func__, __LINE__); | ||
1343 | return -EFAULT; | ||
1344 | } | ||
1345 | return ov5650_set_group_hold(info, &ae); | ||
1346 | } | ||
1347 | default: | ||
1348 | return -EINVAL; | ||
1349 | } | ||
1350 | return 0; | ||
1351 | } | ||
1352 | |||
1353 | static int ov5650_open(struct inode *inode, struct file *file) | ||
1354 | { | ||
1355 | pr_info("%s\n", __func__); | ||
1356 | file->private_data = stereo_ov5650_info; | ||
1357 | ov5650_set_power(1); | ||
1358 | return 0; | ||
1359 | } | ||
1360 | |||
1361 | int ov5650_release(struct inode *inode, struct file *file) | ||
1362 | { | ||
1363 | ov5650_set_power(0); | ||
1364 | file->private_data = NULL; | ||
1365 | return 0; | ||
1366 | } | ||
1367 | |||
1368 | |||
1369 | static const struct file_operations ov5650_fileops = { | ||
1370 | .owner = THIS_MODULE, | ||
1371 | .open = ov5650_open, | ||
1372 | .unlocked_ioctl = ov5650_ioctl, | ||
1373 | .release = ov5650_release, | ||
1374 | }; | ||
1375 | |||
1376 | static struct miscdevice ov5650_device = { | ||
1377 | .minor = MISC_DYNAMIC_MINOR, | ||
1378 | .name = "ov5650", | ||
1379 | .fops = &ov5650_fileops, | ||
1380 | }; | ||
1381 | |||
1382 | static int ov5650_probe_common(void) | ||
1383 | { | ||
1384 | int err; | ||
1385 | |||
1386 | if (!stereo_ov5650_info) { | ||
1387 | stereo_ov5650_info = kzalloc(sizeof(struct ov5650_info), | ||
1388 | GFP_KERNEL); | ||
1389 | if (!stereo_ov5650_info) { | ||
1390 | pr_err("ov5650: Unable to allocate memory!\n"); | ||
1391 | return -ENOMEM; | ||
1392 | } | ||
1393 | |||
1394 | err = misc_register(&ov5650_device); | ||
1395 | if (err) { | ||
1396 | pr_err("ov5650: Unable to register misc device!\n"); | ||
1397 | kfree(stereo_ov5650_info); | ||
1398 | return err; | ||
1399 | } | ||
1400 | } | ||
1401 | return 0; | ||
1402 | } | ||
1403 | |||
1404 | static int ov5650_remove_common(struct i2c_client *client) | ||
1405 | { | ||
1406 | if (stereo_ov5650_info->left.i2c_client || | ||
1407 | stereo_ov5650_info->right.i2c_client) | ||
1408 | return 0; | ||
1409 | |||
1410 | misc_deregister(&ov5650_device); | ||
1411 | kfree(stereo_ov5650_info); | ||
1412 | stereo_ov5650_info = NULL; | ||
1413 | |||
1414 | return 0; | ||
1415 | } | ||
1416 | |||
1417 | static int left_ov5650_probe(struct i2c_client *client, | ||
1418 | const struct i2c_device_id *id) | ||
1419 | { | ||
1420 | int err; | ||
1421 | pr_info("%s: probing sensor.\n", __func__); | ||
1422 | |||
1423 | err = ov5650_probe_common(); | ||
1424 | if (err) | ||
1425 | return err; | ||
1426 | |||
1427 | stereo_ov5650_info->left.pdata = client->dev.platform_data; | ||
1428 | stereo_ov5650_info->left.i2c_client = client; | ||
1429 | |||
1430 | return 0; | ||
1431 | } | ||
1432 | |||
1433 | static int left_ov5650_remove(struct i2c_client *client) | ||
1434 | { | ||
1435 | if (stereo_ov5650_info) { | ||
1436 | stereo_ov5650_info->left.i2c_client = NULL; | ||
1437 | ov5650_remove_common(client); | ||
1438 | } | ||
1439 | return 0; | ||
1440 | } | ||
1441 | |||
1442 | static const struct i2c_device_id left_ov5650_id[] = { | ||
1443 | { "ov5650", 0 }, | ||
1444 | { "ov5650L", 0 }, | ||
1445 | { }, | ||
1446 | }; | ||
1447 | |||
1448 | MODULE_DEVICE_TABLE(i2c, left_ov5650_id); | ||
1449 | |||
1450 | static struct i2c_driver left_ov5650_i2c_driver = { | ||
1451 | .driver = { | ||
1452 | .name = "ov5650", | ||
1453 | .owner = THIS_MODULE, | ||
1454 | }, | ||
1455 | .probe = left_ov5650_probe, | ||
1456 | .remove = left_ov5650_remove, | ||
1457 | .id_table = left_ov5650_id, | ||
1458 | }; | ||
1459 | |||
1460 | static int right_ov5650_probe(struct i2c_client *client, | ||
1461 | const struct i2c_device_id *id) | ||
1462 | { | ||
1463 | int err; | ||
1464 | pr_info("%s: probing sensor.\n", __func__); | ||
1465 | |||
1466 | err = ov5650_probe_common(); | ||
1467 | if (err) | ||
1468 | return err; | ||
1469 | |||
1470 | stereo_ov5650_info->right.pdata = client->dev.platform_data; | ||
1471 | stereo_ov5650_info->right.i2c_client = client; | ||
1472 | |||
1473 | return 0; | ||
1474 | } | ||
1475 | |||
1476 | static int right_ov5650_remove(struct i2c_client *client) | ||
1477 | { | ||
1478 | if (stereo_ov5650_info) { | ||
1479 | stereo_ov5650_info->right.i2c_client = NULL; | ||
1480 | ov5650_remove_common(client); | ||
1481 | } | ||
1482 | return 0; | ||
1483 | } | ||
1484 | |||
1485 | static const struct i2c_device_id right_ov5650_id[] = { | ||
1486 | { "ov5650R", 0 }, | ||
1487 | { }, | ||
1488 | }; | ||
1489 | |||
1490 | MODULE_DEVICE_TABLE(i2c, right_ov5650_id); | ||
1491 | |||
1492 | static struct i2c_driver right_ov5650_i2c_driver = { | ||
1493 | .driver = { | ||
1494 | .name = "ov5650R", | ||
1495 | .owner = THIS_MODULE, | ||
1496 | }, | ||
1497 | .probe = right_ov5650_probe, | ||
1498 | .remove = right_ov5650_remove, | ||
1499 | .id_table = right_ov5650_id, | ||
1500 | }; | ||
1501 | |||
1502 | static int __init ov5650_init(void) | ||
1503 | { | ||
1504 | int ret; | ||
1505 | pr_info("ov5650 sensor driver loading\n"); | ||
1506 | ret = i2c_add_driver(&left_ov5650_i2c_driver); | ||
1507 | if (ret) | ||
1508 | return ret; | ||
1509 | return i2c_add_driver(&right_ov5650_i2c_driver); | ||
1510 | } | ||
1511 | |||
1512 | static void __exit ov5650_exit(void) | ||
1513 | { | ||
1514 | i2c_del_driver(&right_ov5650_i2c_driver); | ||
1515 | i2c_del_driver(&left_ov5650_i2c_driver); | ||
1516 | } | ||
1517 | |||
1518 | module_init(ov5650_init); | ||
1519 | module_exit(ov5650_exit); | ||
1520 | |||