1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2022 Intel Corporation. |
3 | |
4 | #include <linux/acpi.h> |
5 | #include <linux/clk.h> |
6 | #include <linux/delay.h> |
7 | #include <linux/i2c.h> |
8 | #include <linux/module.h> |
9 | #include <linux/pm_runtime.h> |
10 | #include <linux/regulator/consumer.h> |
11 | #include <media/v4l2-ctrls.h> |
12 | #include <media/v4l2-device.h> |
13 | #include <media/v4l2-fwnode.h> |
14 | |
15 | #define OV08D10_SCLK 144000000ULL |
16 | #define OV08D10_XVCLK_19_2 19200000 |
17 | #define OV08D10_ROWCLK 36000 |
18 | #define OV08D10_DATA_LANES 2 |
19 | #define OV08D10_RGB_DEPTH 10 |
20 | |
21 | #define OV08D10_REG_PAGE 0xfd |
22 | #define OV08D10_REG_GLOBAL_EFFECTIVE 0x01 |
23 | #define OV08D10_REG_CHIP_ID_0 0x00 |
24 | #define OV08D10_REG_CHIP_ID_1 0x01 |
25 | #define OV08D10_ID_MASK GENMASK(15, 0) |
26 | #define OV08D10_CHIP_ID 0x5608 |
27 | |
28 | #define OV08D10_REG_MODE_SELECT 0xa0 |
29 | #define OV08D10_MODE_STANDBY 0x00 |
30 | #define OV08D10_MODE_STREAMING 0x01 |
31 | |
32 | /* vertical-timings from sensor */ |
33 | #define OV08D10_REG_VTS_H 0x05 |
34 | #define OV08D10_REG_VTS_L 0x06 |
35 | #define OV08D10_VTS_MAX 0x7fff |
36 | |
37 | /* Exposure controls from sensor */ |
38 | #define OV08D10_REG_EXPOSURE_H 0x02 |
39 | #define OV08D10_REG_EXPOSURE_M 0x03 |
40 | #define OV08D10_REG_EXPOSURE_L 0x04 |
41 | #define OV08D10_EXPOSURE_MIN 6 |
42 | #define OV08D10_EXPOSURE_MAX_MARGIN 6 |
43 | #define OV08D10_EXPOSURE_STEP 1 |
44 | |
45 | /* Analog gain controls from sensor */ |
46 | #define OV08D10_REG_ANALOG_GAIN 0x24 |
47 | #define OV08D10_ANAL_GAIN_MIN 128 |
48 | #define OV08D10_ANAL_GAIN_MAX 2047 |
49 | #define OV08D10_ANAL_GAIN_STEP 1 |
50 | |
51 | /* Digital gain controls from sensor */ |
52 | #define OV08D10_REG_MWB_DGAIN_C 0x21 |
53 | #define OV08D10_REG_MWB_DGAIN_F 0x22 |
54 | #define OV08D10_DGTL_GAIN_MIN 0 |
55 | #define OV08D10_DGTL_GAIN_MAX 4095 |
56 | #define OV08D10_DGTL_GAIN_STEP 1 |
57 | #define OV08D10_DGTL_GAIN_DEFAULT 1024 |
58 | |
59 | /* Test Pattern Control */ |
60 | #define OV08D10_REG_TEST_PATTERN 0x12 |
61 | #define OV08D10_TEST_PATTERN_ENABLE 0x01 |
62 | #define OV08D10_TEST_PATTERN_DISABLE 0x00 |
63 | |
64 | /* Flip Mirror Controls from sensor */ |
65 | #define OV08D10_REG_FLIP_OPT 0x32 |
66 | #define OV08D10_REG_FLIP_MASK 0x3 |
67 | |
68 | #define to_ov08d10(_sd) container_of(_sd, struct ov08d10, sd) |
69 | |
70 | struct ov08d10_reg { |
71 | u8 address; |
72 | u8 val; |
73 | }; |
74 | |
75 | struct ov08d10_reg_list { |
76 | u32 num_of_regs; |
77 | const struct ov08d10_reg *regs; |
78 | }; |
79 | |
80 | struct ov08d10_link_freq_config { |
81 | const struct ov08d10_reg_list reg_list; |
82 | }; |
83 | |
84 | struct ov08d10_mode { |
85 | /* Frame width in pixels */ |
86 | u32 width; |
87 | |
88 | /* Frame height in pixels */ |
89 | u32 height; |
90 | |
91 | /* Horizontal timining size */ |
92 | u32 hts; |
93 | |
94 | /* Default vertical timining size */ |
95 | u32 vts_def; |
96 | |
97 | /* Min vertical timining size */ |
98 | u32 vts_min; |
99 | |
100 | /* Link frequency needed for this resolution */ |
101 | u32 link_freq_index; |
102 | |
103 | /* Sensor register settings for this resolution */ |
104 | const struct ov08d10_reg_list reg_list; |
105 | |
106 | /* Number of data lanes */ |
107 | u8 data_lanes; |
108 | }; |
109 | |
110 | /* 3280x2460, 3264x2448 need 720Mbps/lane, 2 lanes */ |
111 | static const struct ov08d10_reg mipi_data_rate_720mbps[] = { |
112 | {0xfd, 0x00}, |
113 | {0x11, 0x2a}, |
114 | {0x14, 0x43}, |
115 | {0x1a, 0x04}, |
116 | {0x1b, 0xe1}, |
117 | {0x1e, 0x13}, |
118 | {0xb7, 0x02} |
119 | }; |
120 | |
121 | /* 1632x1224 needs 360Mbps/lane, 2 lanes */ |
122 | static const struct ov08d10_reg mipi_data_rate_360mbps[] = { |
123 | {0xfd, 0x00}, |
124 | {0x1a, 0x04}, |
125 | {0x1b, 0xe1}, |
126 | {0x1d, 0x00}, |
127 | {0x1c, 0x19}, |
128 | {0x11, 0x2a}, |
129 | {0x14, 0x54}, |
130 | {0x1e, 0x13}, |
131 | {0xb7, 0x02} |
132 | }; |
133 | |
134 | static const struct ov08d10_reg lane_2_mode_3280x2460[] = { |
135 | /* 3280x2460 resolution */ |
136 | {0xfd, 0x01}, |
137 | {0x12, 0x00}, |
138 | {0x03, 0x12}, |
139 | {0x04, 0x58}, |
140 | {0x07, 0x05}, |
141 | {0x21, 0x02}, |
142 | {0x24, 0x30}, |
143 | {0x33, 0x03}, |
144 | {0x01, 0x03}, |
145 | {0x19, 0x10}, |
146 | {0x42, 0x55}, |
147 | {0x43, 0x00}, |
148 | {0x47, 0x07}, |
149 | {0x48, 0x08}, |
150 | {0xb2, 0x7f}, |
151 | {0xb3, 0x7b}, |
152 | {0xbd, 0x08}, |
153 | {0xd2, 0x57}, |
154 | {0xd3, 0x10}, |
155 | {0xd4, 0x08}, |
156 | {0xd5, 0x08}, |
157 | {0xd6, 0x06}, |
158 | {0xb1, 0x00}, |
159 | {0xb4, 0x00}, |
160 | {0xb7, 0x0a}, |
161 | {0xbc, 0x44}, |
162 | {0xbf, 0x48}, |
163 | {0xc1, 0x10}, |
164 | {0xc3, 0x24}, |
165 | {0xc8, 0x03}, |
166 | {0xc9, 0xf8}, |
167 | {0xe1, 0x33}, |
168 | {0xe2, 0xbb}, |
169 | {0x51, 0x0c}, |
170 | {0x52, 0x0a}, |
171 | {0x57, 0x8c}, |
172 | {0x59, 0x09}, |
173 | {0x5a, 0x08}, |
174 | {0x5e, 0x10}, |
175 | {0x60, 0x02}, |
176 | {0x6d, 0x5c}, |
177 | {0x76, 0x16}, |
178 | {0x7c, 0x11}, |
179 | {0x90, 0x28}, |
180 | {0x91, 0x16}, |
181 | {0x92, 0x1c}, |
182 | {0x93, 0x24}, |
183 | {0x95, 0x48}, |
184 | {0x9c, 0x06}, |
185 | {0xca, 0x0c}, |
186 | {0xce, 0x0d}, |
187 | {0xfd, 0x01}, |
188 | {0xc0, 0x00}, |
189 | {0xdd, 0x18}, |
190 | {0xde, 0x19}, |
191 | {0xdf, 0x32}, |
192 | {0xe0, 0x70}, |
193 | {0xfd, 0x01}, |
194 | {0xc2, 0x05}, |
195 | {0xd7, 0x88}, |
196 | {0xd8, 0x77}, |
197 | {0xd9, 0x00}, |
198 | {0xfd, 0x07}, |
199 | {0x00, 0xf8}, |
200 | {0x01, 0x2b}, |
201 | {0x05, 0x40}, |
202 | {0x08, 0x06}, |
203 | {0x09, 0x11}, |
204 | {0x28, 0x6f}, |
205 | {0x2a, 0x20}, |
206 | {0x2b, 0x05}, |
207 | {0x5e, 0x10}, |
208 | {0x52, 0x00}, |
209 | {0x53, 0x7c}, |
210 | {0x54, 0x00}, |
211 | {0x55, 0x7c}, |
212 | {0x56, 0x00}, |
213 | {0x57, 0x7c}, |
214 | {0x58, 0x00}, |
215 | {0x59, 0x7c}, |
216 | {0xfd, 0x02}, |
217 | {0x9a, 0x30}, |
218 | {0xa8, 0x02}, |
219 | {0xfd, 0x02}, |
220 | {0xa1, 0x01}, |
221 | {0xa2, 0x09}, |
222 | {0xa3, 0x9c}, |
223 | {0xa5, 0x00}, |
224 | {0xa6, 0x0c}, |
225 | {0xa7, 0xd0}, |
226 | {0xfd, 0x00}, |
227 | {0x24, 0x01}, |
228 | {0xc0, 0x16}, |
229 | {0xc1, 0x08}, |
230 | {0xc2, 0x30}, |
231 | {0x8e, 0x0c}, |
232 | {0x8f, 0xd0}, |
233 | {0x90, 0x09}, |
234 | {0x91, 0x9c}, |
235 | {0xfd, 0x05}, |
236 | {0x04, 0x40}, |
237 | {0x07, 0x00}, |
238 | {0x0d, 0x01}, |
239 | {0x0f, 0x01}, |
240 | {0x10, 0x00}, |
241 | {0x11, 0x00}, |
242 | {0x12, 0x0c}, |
243 | {0x13, 0xcf}, |
244 | {0x14, 0x00}, |
245 | {0x15, 0x00}, |
246 | {0xfd, 0x00}, |
247 | {0x20, 0x0f}, |
248 | {0xe7, 0x03}, |
249 | {0xe7, 0x00} |
250 | }; |
251 | |
252 | static const struct ov08d10_reg lane_2_mode_3264x2448[] = { |
253 | /* 3264x2448 resolution */ |
254 | {0xfd, 0x01}, |
255 | {0x12, 0x00}, |
256 | {0x03, 0x12}, |
257 | {0x04, 0x58}, |
258 | {0x07, 0x05}, |
259 | {0x21, 0x02}, |
260 | {0x24, 0x30}, |
261 | {0x33, 0x03}, |
262 | {0x01, 0x03}, |
263 | {0x19, 0x10}, |
264 | {0x42, 0x55}, |
265 | {0x43, 0x00}, |
266 | {0x47, 0x07}, |
267 | {0x48, 0x08}, |
268 | {0xb2, 0x7f}, |
269 | {0xb3, 0x7b}, |
270 | {0xbd, 0x08}, |
271 | {0xd2, 0x57}, |
272 | {0xd3, 0x10}, |
273 | {0xd4, 0x08}, |
274 | {0xd5, 0x08}, |
275 | {0xd6, 0x06}, |
276 | {0xb1, 0x00}, |
277 | {0xb4, 0x00}, |
278 | {0xb7, 0x0a}, |
279 | {0xbc, 0x44}, |
280 | {0xbf, 0x48}, |
281 | {0xc1, 0x10}, |
282 | {0xc3, 0x24}, |
283 | {0xc8, 0x03}, |
284 | {0xc9, 0xf8}, |
285 | {0xe1, 0x33}, |
286 | {0xe2, 0xbb}, |
287 | {0x51, 0x0c}, |
288 | {0x52, 0x0a}, |
289 | {0x57, 0x8c}, |
290 | {0x59, 0x09}, |
291 | {0x5a, 0x08}, |
292 | {0x5e, 0x10}, |
293 | {0x60, 0x02}, |
294 | {0x6d, 0x5c}, |
295 | {0x76, 0x16}, |
296 | {0x7c, 0x11}, |
297 | {0x90, 0x28}, |
298 | {0x91, 0x16}, |
299 | {0x92, 0x1c}, |
300 | {0x93, 0x24}, |
301 | {0x95, 0x48}, |
302 | {0x9c, 0x06}, |
303 | {0xca, 0x0c}, |
304 | {0xce, 0x0d}, |
305 | {0xfd, 0x01}, |
306 | {0xc0, 0x00}, |
307 | {0xdd, 0x18}, |
308 | {0xde, 0x19}, |
309 | {0xdf, 0x32}, |
310 | {0xe0, 0x70}, |
311 | {0xfd, 0x01}, |
312 | {0xc2, 0x05}, |
313 | {0xd7, 0x88}, |
314 | {0xd8, 0x77}, |
315 | {0xd9, 0x00}, |
316 | {0xfd, 0x07}, |
317 | {0x00, 0xf8}, |
318 | {0x01, 0x2b}, |
319 | {0x05, 0x40}, |
320 | {0x08, 0x06}, |
321 | {0x09, 0x11}, |
322 | {0x28, 0x6f}, |
323 | {0x2a, 0x20}, |
324 | {0x2b, 0x05}, |
325 | {0x5e, 0x10}, |
326 | {0x52, 0x00}, |
327 | {0x53, 0x7c}, |
328 | {0x54, 0x00}, |
329 | {0x55, 0x7c}, |
330 | {0x56, 0x00}, |
331 | {0x57, 0x7c}, |
332 | {0x58, 0x00}, |
333 | {0x59, 0x7c}, |
334 | {0xfd, 0x02}, |
335 | {0x9a, 0x30}, |
336 | {0xa8, 0x02}, |
337 | {0xfd, 0x02}, |
338 | {0xa1, 0x09}, |
339 | {0xa2, 0x09}, |
340 | {0xa3, 0x90}, |
341 | {0xa5, 0x08}, |
342 | {0xa6, 0x0c}, |
343 | {0xa7, 0xc0}, |
344 | {0xfd, 0x00}, |
345 | {0x24, 0x01}, |
346 | {0xc0, 0x16}, |
347 | {0xc1, 0x08}, |
348 | {0xc2, 0x30}, |
349 | {0x8e, 0x0c}, |
350 | {0x8f, 0xc0}, |
351 | {0x90, 0x09}, |
352 | {0x91, 0x90}, |
353 | {0xfd, 0x05}, |
354 | {0x04, 0x40}, |
355 | {0x07, 0x00}, |
356 | {0x0d, 0x01}, |
357 | {0x0f, 0x01}, |
358 | {0x10, 0x00}, |
359 | {0x11, 0x00}, |
360 | {0x12, 0x0c}, |
361 | {0x13, 0xcf}, |
362 | {0x14, 0x00}, |
363 | {0x15, 0x00}, |
364 | {0xfd, 0x00}, |
365 | {0x20, 0x0f}, |
366 | {0xe7, 0x03}, |
367 | {0xe7, 0x00} |
368 | }; |
369 | |
370 | static const struct ov08d10_reg lane_2_mode_1632x1224[] = { |
371 | /* 1640x1232 resolution */ |
372 | {0xfd, 0x01}, |
373 | {0x1a, 0x0a}, |
374 | {0x1b, 0x08}, |
375 | {0x2a, 0x01}, |
376 | {0x2b, 0x9a}, |
377 | {0xfd, 0x01}, |
378 | {0x12, 0x00}, |
379 | {0x03, 0x05}, |
380 | {0x04, 0xe2}, |
381 | {0x07, 0x05}, |
382 | {0x21, 0x02}, |
383 | {0x24, 0x30}, |
384 | {0x33, 0x03}, |
385 | {0x31, 0x06}, |
386 | {0x33, 0x03}, |
387 | {0x01, 0x03}, |
388 | {0x19, 0x10}, |
389 | {0x42, 0x55}, |
390 | {0x43, 0x00}, |
391 | {0x47, 0x07}, |
392 | {0x48, 0x08}, |
393 | {0xb2, 0x7f}, |
394 | {0xb3, 0x7b}, |
395 | {0xbd, 0x08}, |
396 | {0xd2, 0x57}, |
397 | {0xd3, 0x10}, |
398 | {0xd4, 0x08}, |
399 | {0xd5, 0x08}, |
400 | {0xd6, 0x06}, |
401 | {0xb1, 0x00}, |
402 | {0xb4, 0x00}, |
403 | {0xb7, 0x0a}, |
404 | {0xbc, 0x44}, |
405 | {0xbf, 0x48}, |
406 | {0xc1, 0x10}, |
407 | {0xc3, 0x24}, |
408 | {0xc8, 0x03}, |
409 | {0xc9, 0xf8}, |
410 | {0xe1, 0x33}, |
411 | {0xe2, 0xbb}, |
412 | {0x51, 0x0c}, |
413 | {0x52, 0x0a}, |
414 | {0x57, 0x8c}, |
415 | {0x59, 0x09}, |
416 | {0x5a, 0x08}, |
417 | {0x5e, 0x10}, |
418 | {0x60, 0x02}, |
419 | {0x6d, 0x5c}, |
420 | {0x76, 0x16}, |
421 | {0x7c, 0x1a}, |
422 | {0x90, 0x28}, |
423 | {0x91, 0x16}, |
424 | {0x92, 0x1c}, |
425 | {0x93, 0x24}, |
426 | {0x95, 0x48}, |
427 | {0x9c, 0x06}, |
428 | {0xca, 0x0c}, |
429 | {0xce, 0x0d}, |
430 | {0xfd, 0x01}, |
431 | {0xc0, 0x00}, |
432 | {0xdd, 0x18}, |
433 | {0xde, 0x19}, |
434 | {0xdf, 0x32}, |
435 | {0xe0, 0x70}, |
436 | {0xfd, 0x01}, |
437 | {0xc2, 0x05}, |
438 | {0xd7, 0x88}, |
439 | {0xd8, 0x77}, |
440 | {0xd9, 0x00}, |
441 | {0xfd, 0x07}, |
442 | {0x00, 0xf8}, |
443 | {0x01, 0x2b}, |
444 | {0x05, 0x40}, |
445 | {0x08, 0x03}, |
446 | {0x09, 0x08}, |
447 | {0x28, 0x6f}, |
448 | {0x2a, 0x20}, |
449 | {0x2b, 0x05}, |
450 | {0x2c, 0x01}, |
451 | {0x50, 0x02}, |
452 | {0x51, 0x03}, |
453 | {0x5e, 0x00}, |
454 | {0x52, 0x00}, |
455 | {0x53, 0x7c}, |
456 | {0x54, 0x00}, |
457 | {0x55, 0x7c}, |
458 | {0x56, 0x00}, |
459 | {0x57, 0x7c}, |
460 | {0x58, 0x00}, |
461 | {0x59, 0x7c}, |
462 | {0xfd, 0x02}, |
463 | {0x9a, 0x30}, |
464 | {0xa8, 0x02}, |
465 | {0xfd, 0x02}, |
466 | {0xa9, 0x04}, |
467 | {0xaa, 0xd0}, |
468 | {0xab, 0x06}, |
469 | {0xac, 0x68}, |
470 | {0xa1, 0x09}, |
471 | {0xa2, 0x04}, |
472 | {0xa3, 0xc8}, |
473 | {0xa5, 0x04}, |
474 | {0xa6, 0x06}, |
475 | {0xa7, 0x60}, |
476 | {0xfd, 0x05}, |
477 | {0x06, 0x80}, |
478 | {0x18, 0x06}, |
479 | {0x19, 0x68}, |
480 | {0xfd, 0x00}, |
481 | {0x24, 0x01}, |
482 | {0xc0, 0x16}, |
483 | {0xc1, 0x08}, |
484 | {0xc2, 0x30}, |
485 | {0x8e, 0x06}, |
486 | {0x8f, 0x60}, |
487 | {0x90, 0x04}, |
488 | {0x91, 0xc8}, |
489 | {0x93, 0x0e}, |
490 | {0x94, 0x77}, |
491 | {0x95, 0x77}, |
492 | {0x96, 0x10}, |
493 | {0x98, 0x88}, |
494 | {0x9c, 0x1a}, |
495 | {0xfd, 0x05}, |
496 | {0x04, 0x40}, |
497 | {0x07, 0x99}, |
498 | {0x0d, 0x03}, |
499 | {0x0f, 0x03}, |
500 | {0x10, 0x00}, |
501 | {0x11, 0x00}, |
502 | {0x12, 0x0c}, |
503 | {0x13, 0xcf}, |
504 | {0x14, 0x00}, |
505 | {0x15, 0x00}, |
506 | {0xfd, 0x00}, |
507 | {0x20, 0x0f}, |
508 | {0xe7, 0x03}, |
509 | {0xe7, 0x00}, |
510 | }; |
511 | |
512 | static const char * const [] = { |
513 | "Disabled" , |
514 | "Standard Color Bar" , |
515 | }; |
516 | |
517 | struct ov08d10 { |
518 | struct v4l2_subdev sd; |
519 | struct media_pad pad; |
520 | struct v4l2_ctrl_handler ctrl_handler; |
521 | |
522 | struct clk *xvclk; |
523 | |
524 | /* V4L2 Controls */ |
525 | struct v4l2_ctrl *link_freq; |
526 | struct v4l2_ctrl *pixel_rate; |
527 | struct v4l2_ctrl *vblank; |
528 | struct v4l2_ctrl *hblank; |
529 | struct v4l2_ctrl *vflip; |
530 | struct v4l2_ctrl *hflip; |
531 | struct v4l2_ctrl *exposure; |
532 | |
533 | /* Current mode */ |
534 | const struct ov08d10_mode *cur_mode; |
535 | |
536 | /* To serialize asynchronus callbacks */ |
537 | struct mutex mutex; |
538 | |
539 | /* lanes index */ |
540 | u8 nlanes; |
541 | |
542 | const struct ov08d10_lane_cfg *priv_lane; |
543 | u8 modes_size; |
544 | }; |
545 | |
546 | struct ov08d10_lane_cfg { |
547 | const s64 [2]; |
548 | const struct ov08d10_link_freq_config link_freq_configs[2]; |
549 | const struct ov08d10_mode sp_modes[3]; |
550 | }; |
551 | |
552 | static const struct ov08d10_lane_cfg lane_cfg_2 = { |
553 | { |
554 | 720000000, |
555 | 360000000, |
556 | }, |
557 | {{ |
558 | .reg_list = { |
559 | .num_of_regs = |
560 | ARRAY_SIZE(mipi_data_rate_720mbps), |
561 | .regs = mipi_data_rate_720mbps, |
562 | } |
563 | }, |
564 | { |
565 | .reg_list = { |
566 | .num_of_regs = |
567 | ARRAY_SIZE(mipi_data_rate_360mbps), |
568 | .regs = mipi_data_rate_360mbps, |
569 | } |
570 | }}, |
571 | {{ |
572 | .width = 3280, |
573 | .height = 2460, |
574 | .hts = 1840, |
575 | .vts_def = 2504, |
576 | .vts_min = 2504, |
577 | .reg_list = { |
578 | .num_of_regs = ARRAY_SIZE(lane_2_mode_3280x2460), |
579 | .regs = lane_2_mode_3280x2460, |
580 | }, |
581 | .link_freq_index = 0, |
582 | .data_lanes = 2, |
583 | }, |
584 | { |
585 | .width = 3264, |
586 | .height = 2448, |
587 | .hts = 1840, |
588 | .vts_def = 2504, |
589 | .vts_min = 2504, |
590 | .reg_list = { |
591 | .num_of_regs = ARRAY_SIZE(lane_2_mode_3264x2448), |
592 | .regs = lane_2_mode_3264x2448, |
593 | }, |
594 | .link_freq_index = 0, |
595 | .data_lanes = 2, |
596 | }, |
597 | { |
598 | .width = 1632, |
599 | .height = 1224, |
600 | .hts = 1912, |
601 | .vts_def = 3736, |
602 | .vts_min = 3736, |
603 | .reg_list = { |
604 | .num_of_regs = ARRAY_SIZE(lane_2_mode_1632x1224), |
605 | .regs = lane_2_mode_1632x1224, |
606 | }, |
607 | .link_freq_index = 1, |
608 | .data_lanes = 2, |
609 | }} |
610 | }; |
611 | |
612 | static u32 ov08d10_get_format_code(struct ov08d10 *ov08d10) |
613 | { |
614 | static const u32 codes[2][2] = { |
615 | { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10}, |
616 | { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10}, |
617 | }; |
618 | |
619 | return codes[ov08d10->vflip->val][ov08d10->hflip->val]; |
620 | } |
621 | |
622 | static unsigned int ov08d10_modes_num(const struct ov08d10 *ov08d10) |
623 | { |
624 | unsigned int i, count = 0; |
625 | |
626 | for (i = 0; i < ARRAY_SIZE(ov08d10->priv_lane->sp_modes); i++) { |
627 | if (ov08d10->priv_lane->sp_modes[i].width == 0) |
628 | break; |
629 | count++; |
630 | } |
631 | |
632 | return count; |
633 | } |
634 | |
635 | static u64 to_rate(const s64 *, |
636 | u32 f_index, u8 nlanes) |
637 | { |
638 | u64 pixel_rate = link_freq_menu[f_index] * 2 * nlanes; |
639 | |
640 | do_div(pixel_rate, OV08D10_RGB_DEPTH); |
641 | |
642 | return pixel_rate; |
643 | } |
644 | |
645 | static u64 to_pixels_per_line(const s64 *, u32 hts, |
646 | u32 f_index, u8 nlanes) |
647 | { |
648 | u64 ppl = hts * to_rate(link_freq_menu, f_index, nlanes); |
649 | |
650 | do_div(ppl, OV08D10_SCLK); |
651 | |
652 | return ppl; |
653 | } |
654 | |
655 | static int ov08d10_write_reg_list(struct ov08d10 *ov08d10, |
656 | const struct ov08d10_reg_list *r_list) |
657 | { |
658 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08d10->sd); |
659 | unsigned int i; |
660 | int ret; |
661 | |
662 | for (i = 0; i < r_list->num_of_regs; i++) { |
663 | ret = i2c_smbus_write_byte_data(client, command: r_list->regs[i].address, |
664 | value: r_list->regs[i].val); |
665 | if (ret) { |
666 | dev_err_ratelimited(&client->dev, |
667 | "failed to write reg 0x%2.2x. error = %d" , |
668 | r_list->regs[i].address, ret); |
669 | return ret; |
670 | } |
671 | } |
672 | |
673 | return 0; |
674 | } |
675 | |
676 | static int ov08d10_update_analog_gain(struct ov08d10 *ov08d10, u32 a_gain) |
677 | { |
678 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08d10->sd); |
679 | u8 val; |
680 | int ret; |
681 | |
682 | val = ((a_gain >> 3) & 0xFF); |
683 | /* CIS control registers */ |
684 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, value: 0x01); |
685 | if (ret < 0) |
686 | return ret; |
687 | |
688 | /* update AGAIN */ |
689 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_ANALOG_GAIN, value: val); |
690 | if (ret < 0) |
691 | return ret; |
692 | |
693 | return i2c_smbus_write_byte_data(client, |
694 | OV08D10_REG_GLOBAL_EFFECTIVE, value: 0x01); |
695 | } |
696 | |
697 | static int ov08d10_update_digital_gain(struct ov08d10 *ov08d10, u32 d_gain) |
698 | { |
699 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08d10->sd); |
700 | u8 val; |
701 | int ret; |
702 | |
703 | d_gain = (d_gain >> 1); |
704 | /* CIS control registers */ |
705 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, value: 0x01); |
706 | if (ret < 0) |
707 | return ret; |
708 | |
709 | val = ((d_gain >> 8) & 0x3F); |
710 | /* update DGAIN */ |
711 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_MWB_DGAIN_C, value: val); |
712 | if (ret < 0) |
713 | return ret; |
714 | |
715 | val = d_gain & 0xFF; |
716 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_MWB_DGAIN_F, value: val); |
717 | if (ret < 0) |
718 | return ret; |
719 | |
720 | return i2c_smbus_write_byte_data(client, |
721 | OV08D10_REG_GLOBAL_EFFECTIVE, value: 0x01); |
722 | } |
723 | |
724 | static int ov08d10_set_exposure(struct ov08d10 *ov08d10, u32 exposure) |
725 | { |
726 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08d10->sd); |
727 | u8 val; |
728 | u8 hts_h, hts_l; |
729 | u32 hts, cur_vts, exp_cal; |
730 | int ret; |
731 | |
732 | cur_vts = ov08d10->cur_mode->vts_def; |
733 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, value: 0x01); |
734 | if (ret < 0) |
735 | return ret; |
736 | |
737 | hts_h = i2c_smbus_read_byte_data(client, command: 0x37); |
738 | hts_l = i2c_smbus_read_byte_data(client, command: 0x38); |
739 | hts = ((hts_h << 8) | (hts_l)); |
740 | exp_cal = 66 * OV08D10_ROWCLK / hts; |
741 | exposure = exposure * exp_cal / (cur_vts - OV08D10_EXPOSURE_MAX_MARGIN); |
742 | /* CIS control registers */ |
743 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, value: 0x01); |
744 | if (ret < 0) |
745 | return ret; |
746 | |
747 | /* update exposure */ |
748 | val = ((exposure >> 16) & 0xFF); |
749 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_EXPOSURE_H, value: val); |
750 | if (ret < 0) |
751 | return ret; |
752 | |
753 | val = ((exposure >> 8) & 0xFF); |
754 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_EXPOSURE_M, value: val); |
755 | if (ret < 0) |
756 | return ret; |
757 | |
758 | val = exposure & 0xFF; |
759 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_EXPOSURE_L, value: val); |
760 | if (ret < 0) |
761 | return ret; |
762 | |
763 | return i2c_smbus_write_byte_data(client, |
764 | OV08D10_REG_GLOBAL_EFFECTIVE, value: 0x01); |
765 | } |
766 | |
767 | static int ov08d10_set_vblank(struct ov08d10 *ov08d10, u32 vblank) |
768 | { |
769 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08d10->sd); |
770 | u8 val; |
771 | int ret; |
772 | |
773 | /* CIS control registers */ |
774 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, value: 0x01); |
775 | if (ret < 0) |
776 | return ret; |
777 | |
778 | val = ((vblank >> 8) & 0xFF); |
779 | /* update vblank */ |
780 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_VTS_H, value: val); |
781 | if (ret < 0) |
782 | return ret; |
783 | |
784 | val = vblank & 0xFF; |
785 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_VTS_L, value: val); |
786 | if (ret < 0) |
787 | return ret; |
788 | |
789 | return i2c_smbus_write_byte_data(client, |
790 | OV08D10_REG_GLOBAL_EFFECTIVE, value: 0x01); |
791 | } |
792 | |
793 | static int ov08d10_test_pattern(struct ov08d10 *ov08d10, u32 pattern) |
794 | { |
795 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08d10->sd); |
796 | u8 val; |
797 | int ret; |
798 | |
799 | if (pattern) |
800 | val = OV08D10_TEST_PATTERN_ENABLE; |
801 | else |
802 | val = OV08D10_TEST_PATTERN_DISABLE; |
803 | |
804 | /* CIS control registers */ |
805 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, value: 0x01); |
806 | if (ret < 0) |
807 | return ret; |
808 | |
809 | ret = i2c_smbus_write_byte_data(client, |
810 | OV08D10_REG_TEST_PATTERN, value: val); |
811 | if (ret < 0) |
812 | return ret; |
813 | |
814 | return i2c_smbus_write_byte_data(client, |
815 | OV08D10_REG_GLOBAL_EFFECTIVE, value: 0x01); |
816 | } |
817 | |
818 | static int ov08d10_set_ctrl_flip(struct ov08d10 *ov08d10, u32 ctrl_val) |
819 | { |
820 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08d10->sd); |
821 | u8 val; |
822 | int ret; |
823 | |
824 | /* System control registers */ |
825 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, value: 0x01); |
826 | if (ret < 0) |
827 | return ret; |
828 | |
829 | ret = i2c_smbus_read_byte_data(client, OV08D10_REG_FLIP_OPT); |
830 | if (ret < 0) |
831 | return ret; |
832 | |
833 | val = ret | (ctrl_val & OV08D10_REG_FLIP_MASK); |
834 | |
835 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, value: 0x01); |
836 | if (ret < 0) |
837 | return ret; |
838 | |
839 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_FLIP_OPT, value: val); |
840 | |
841 | if (ret < 0) |
842 | return ret; |
843 | |
844 | return i2c_smbus_write_byte_data(client, |
845 | OV08D10_REG_GLOBAL_EFFECTIVE, value: 0x01); |
846 | } |
847 | |
848 | static int ov08d10_set_ctrl(struct v4l2_ctrl *ctrl) |
849 | { |
850 | struct ov08d10 *ov08d10 = container_of(ctrl->handler, |
851 | struct ov08d10, ctrl_handler); |
852 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08d10->sd); |
853 | s64 exposure_max; |
854 | int ret; |
855 | |
856 | /* Propagate change of current control to all related controls */ |
857 | if (ctrl->id == V4L2_CID_VBLANK) { |
858 | /* Update max exposure while meeting expected vblanking */ |
859 | exposure_max = ov08d10->cur_mode->height + ctrl->val - |
860 | OV08D10_EXPOSURE_MAX_MARGIN; |
861 | __v4l2_ctrl_modify_range(ctrl: ov08d10->exposure, |
862 | min: ov08d10->exposure->minimum, |
863 | max: exposure_max, step: ov08d10->exposure->step, |
864 | def: exposure_max); |
865 | } |
866 | |
867 | /* V4L2 controls values will be applied only when power is already up */ |
868 | if (!pm_runtime_get_if_in_use(dev: &client->dev)) |
869 | return 0; |
870 | |
871 | switch (ctrl->id) { |
872 | case V4L2_CID_ANALOGUE_GAIN: |
873 | ret = ov08d10_update_analog_gain(ov08d10, a_gain: ctrl->val); |
874 | break; |
875 | |
876 | case V4L2_CID_DIGITAL_GAIN: |
877 | ret = ov08d10_update_digital_gain(ov08d10, d_gain: ctrl->val); |
878 | break; |
879 | |
880 | case V4L2_CID_EXPOSURE: |
881 | ret = ov08d10_set_exposure(ov08d10, exposure: ctrl->val); |
882 | break; |
883 | |
884 | case V4L2_CID_VBLANK: |
885 | ret = ov08d10_set_vblank(ov08d10, vblank: ctrl->val); |
886 | break; |
887 | |
888 | case V4L2_CID_TEST_PATTERN: |
889 | ret = ov08d10_test_pattern(ov08d10, pattern: ctrl->val); |
890 | break; |
891 | |
892 | case V4L2_CID_HFLIP: |
893 | case V4L2_CID_VFLIP: |
894 | ret = ov08d10_set_ctrl_flip(ov08d10, |
895 | ctrl_val: ov08d10->hflip->val | |
896 | ov08d10->vflip->val << 1); |
897 | break; |
898 | |
899 | default: |
900 | ret = -EINVAL; |
901 | break; |
902 | } |
903 | |
904 | pm_runtime_put(dev: &client->dev); |
905 | |
906 | return ret; |
907 | } |
908 | |
909 | static const struct v4l2_ctrl_ops ov08d10_ctrl_ops = { |
910 | .s_ctrl = ov08d10_set_ctrl, |
911 | }; |
912 | |
913 | static int ov08d10_init_controls(struct ov08d10 *ov08d10) |
914 | { |
915 | struct v4l2_ctrl_handler *ctrl_hdlr; |
916 | u8 link_freq_size; |
917 | s64 exposure_max; |
918 | s64 vblank_def; |
919 | s64 vblank_min; |
920 | s64 h_blank; |
921 | s64 pixel_rate_max; |
922 | const struct ov08d10_mode *mode; |
923 | int ret; |
924 | |
925 | ctrl_hdlr = &ov08d10->ctrl_handler; |
926 | ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); |
927 | if (ret) |
928 | return ret; |
929 | |
930 | ctrl_hdlr->lock = &ov08d10->mutex; |
931 | link_freq_size = ARRAY_SIZE(ov08d10->priv_lane->link_freq_menu); |
932 | ov08d10->link_freq = |
933 | v4l2_ctrl_new_int_menu(hdl: ctrl_hdlr, ops: &ov08d10_ctrl_ops, |
934 | V4L2_CID_LINK_FREQ, |
935 | max: link_freq_size - 1, |
936 | def: 0, |
937 | qmenu_int: ov08d10->priv_lane->link_freq_menu); |
938 | if (ov08d10->link_freq) |
939 | ov08d10->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
940 | |
941 | pixel_rate_max = to_rate(link_freq_menu: ov08d10->priv_lane->link_freq_menu, f_index: 0, |
942 | nlanes: ov08d10->cur_mode->data_lanes); |
943 | ov08d10->pixel_rate = |
944 | v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &ov08d10_ctrl_ops, |
945 | V4L2_CID_PIXEL_RATE, min: 0, max: pixel_rate_max, step: 1, |
946 | def: pixel_rate_max); |
947 | |
948 | mode = ov08d10->cur_mode; |
949 | vblank_def = mode->vts_def - mode->height; |
950 | vblank_min = mode->vts_min - mode->height; |
951 | ov08d10->vblank = |
952 | v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &ov08d10_ctrl_ops, |
953 | V4L2_CID_VBLANK, min: vblank_min, |
954 | OV08D10_VTS_MAX - mode->height, step: 1, |
955 | def: vblank_def); |
956 | |
957 | h_blank = to_pixels_per_line(link_freq_menu: ov08d10->priv_lane->link_freq_menu, |
958 | hts: mode->hts, f_index: mode->link_freq_index, |
959 | nlanes: mode->data_lanes) - |
960 | mode->width; |
961 | ov08d10->hblank = v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &ov08d10_ctrl_ops, |
962 | V4L2_CID_HBLANK, min: h_blank, max: h_blank, |
963 | step: 1, def: h_blank); |
964 | if (ov08d10->hblank) |
965 | ov08d10->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
966 | |
967 | v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &ov08d10_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, |
968 | OV08D10_ANAL_GAIN_MIN, OV08D10_ANAL_GAIN_MAX, |
969 | OV08D10_ANAL_GAIN_STEP, OV08D10_ANAL_GAIN_MIN); |
970 | |
971 | v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &ov08d10_ctrl_ops, V4L2_CID_DIGITAL_GAIN, |
972 | OV08D10_DGTL_GAIN_MIN, OV08D10_DGTL_GAIN_MAX, |
973 | OV08D10_DGTL_GAIN_STEP, OV08D10_DGTL_GAIN_DEFAULT); |
974 | |
975 | exposure_max = mode->vts_def - OV08D10_EXPOSURE_MAX_MARGIN; |
976 | ov08d10->exposure = v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &ov08d10_ctrl_ops, |
977 | V4L2_CID_EXPOSURE, |
978 | OV08D10_EXPOSURE_MIN, |
979 | max: exposure_max, |
980 | OV08D10_EXPOSURE_STEP, |
981 | def: exposure_max); |
982 | |
983 | v4l2_ctrl_new_std_menu_items(hdl: ctrl_hdlr, ops: &ov08d10_ctrl_ops, |
984 | V4L2_CID_TEST_PATTERN, |
985 | ARRAY_SIZE(ov08d10_test_pattern_menu) - 1, |
986 | mask: 0, def: 0, qmenu: ov08d10_test_pattern_menu); |
987 | |
988 | ov08d10->hflip = v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &ov08d10_ctrl_ops, |
989 | V4L2_CID_HFLIP, min: 0, max: 1, step: 1, def: 0); |
990 | if (ov08d10->hflip) |
991 | ov08d10->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; |
992 | ov08d10->vflip = v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &ov08d10_ctrl_ops, |
993 | V4L2_CID_VFLIP, min: 0, max: 1, step: 1, def: 0); |
994 | if (ov08d10->vflip) |
995 | ov08d10->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; |
996 | |
997 | if (ctrl_hdlr->error) |
998 | return ctrl_hdlr->error; |
999 | |
1000 | ov08d10->sd.ctrl_handler = ctrl_hdlr; |
1001 | |
1002 | return 0; |
1003 | } |
1004 | |
1005 | static void ov08d10_update_pad_format(struct ov08d10 *ov08d10, |
1006 | const struct ov08d10_mode *mode, |
1007 | struct v4l2_mbus_framefmt *fmt) |
1008 | { |
1009 | fmt->width = mode->width; |
1010 | fmt->height = mode->height; |
1011 | fmt->code = ov08d10_get_format_code(ov08d10); |
1012 | fmt->field = V4L2_FIELD_NONE; |
1013 | } |
1014 | |
1015 | static int ov08d10_start_streaming(struct ov08d10 *ov08d10) |
1016 | { |
1017 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08d10->sd); |
1018 | const struct ov08d10_reg_list *reg_list; |
1019 | int link_freq_index, ret; |
1020 | |
1021 | link_freq_index = ov08d10->cur_mode->link_freq_index; |
1022 | reg_list = |
1023 | &ov08d10->priv_lane->link_freq_configs[link_freq_index].reg_list; |
1024 | |
1025 | /* soft reset */ |
1026 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, value: 0x00); |
1027 | if (ret < 0) { |
1028 | dev_err(&client->dev, "failed to reset sensor" ); |
1029 | return ret; |
1030 | } |
1031 | ret = i2c_smbus_write_byte_data(client, command: 0x20, value: 0x0e); |
1032 | if (ret < 0) { |
1033 | dev_err(&client->dev, "failed to reset sensor" ); |
1034 | return ret; |
1035 | } |
1036 | usleep_range(min: 3000, max: 4000); |
1037 | ret = i2c_smbus_write_byte_data(client, command: 0x20, value: 0x0b); |
1038 | if (ret < 0) { |
1039 | dev_err(&client->dev, "failed to reset sensor" ); |
1040 | return ret; |
1041 | } |
1042 | |
1043 | /* update sensor setting */ |
1044 | ret = ov08d10_write_reg_list(ov08d10, r_list: reg_list); |
1045 | if (ret) { |
1046 | dev_err(&client->dev, "failed to set plls" ); |
1047 | return ret; |
1048 | } |
1049 | |
1050 | reg_list = &ov08d10->cur_mode->reg_list; |
1051 | ret = ov08d10_write_reg_list(ov08d10, r_list: reg_list); |
1052 | if (ret) { |
1053 | dev_err(&client->dev, "failed to set mode" ); |
1054 | return ret; |
1055 | } |
1056 | |
1057 | ret = __v4l2_ctrl_handler_setup(hdl: ov08d10->sd.ctrl_handler); |
1058 | if (ret) |
1059 | return ret; |
1060 | |
1061 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, value: 0x00); |
1062 | if (ret < 0) |
1063 | return ret; |
1064 | |
1065 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_MODE_SELECT, |
1066 | OV08D10_MODE_STREAMING); |
1067 | if (ret < 0) |
1068 | return ret; |
1069 | |
1070 | return i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, value: 0x01); |
1071 | } |
1072 | |
1073 | static void ov08d10_stop_streaming(struct ov08d10 *ov08d10) |
1074 | { |
1075 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08d10->sd); |
1076 | int ret; |
1077 | |
1078 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, value: 0x00); |
1079 | if (ret < 0) { |
1080 | dev_err(&client->dev, "failed to stop streaming" ); |
1081 | return; |
1082 | } |
1083 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_MODE_SELECT, |
1084 | OV08D10_MODE_STANDBY); |
1085 | if (ret < 0) { |
1086 | dev_err(&client->dev, "failed to stop streaming" ); |
1087 | return; |
1088 | } |
1089 | |
1090 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, value: 0x01); |
1091 | if (ret < 0) { |
1092 | dev_err(&client->dev, "failed to stop streaming" ); |
1093 | return; |
1094 | } |
1095 | } |
1096 | |
1097 | static int ov08d10_set_stream(struct v4l2_subdev *sd, int enable) |
1098 | { |
1099 | struct ov08d10 *ov08d10 = to_ov08d10(sd); |
1100 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1101 | int ret = 0; |
1102 | |
1103 | mutex_lock(&ov08d10->mutex); |
1104 | if (enable) { |
1105 | ret = pm_runtime_resume_and_get(dev: &client->dev); |
1106 | if (ret < 0) { |
1107 | mutex_unlock(lock: &ov08d10->mutex); |
1108 | return ret; |
1109 | } |
1110 | |
1111 | ret = ov08d10_start_streaming(ov08d10); |
1112 | if (ret) { |
1113 | enable = 0; |
1114 | ov08d10_stop_streaming(ov08d10); |
1115 | pm_runtime_put(dev: &client->dev); |
1116 | } |
1117 | } else { |
1118 | ov08d10_stop_streaming(ov08d10); |
1119 | pm_runtime_put(dev: &client->dev); |
1120 | } |
1121 | |
1122 | /* vflip and hflip cannot change during streaming */ |
1123 | __v4l2_ctrl_grab(ctrl: ov08d10->vflip, grabbed: enable); |
1124 | __v4l2_ctrl_grab(ctrl: ov08d10->hflip, grabbed: enable); |
1125 | |
1126 | mutex_unlock(lock: &ov08d10->mutex); |
1127 | |
1128 | return ret; |
1129 | } |
1130 | |
1131 | static int ov08d10_set_format(struct v4l2_subdev *sd, |
1132 | struct v4l2_subdev_state *sd_state, |
1133 | struct v4l2_subdev_format *fmt) |
1134 | { |
1135 | struct ov08d10 *ov08d10 = to_ov08d10(sd); |
1136 | const struct ov08d10_mode *mode; |
1137 | s32 vblank_def, h_blank; |
1138 | s64 pixel_rate; |
1139 | |
1140 | mode = v4l2_find_nearest_size(ov08d10->priv_lane->sp_modes, |
1141 | ov08d10->modes_size, |
1142 | width, height, fmt->format.width, |
1143 | fmt->format.height); |
1144 | |
1145 | mutex_lock(&ov08d10->mutex); |
1146 | ov08d10_update_pad_format(ov08d10, mode, fmt: &fmt->format); |
1147 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
1148 | *v4l2_subdev_state_get_format(sd_state, fmt->pad) = |
1149 | fmt->format; |
1150 | } else { |
1151 | ov08d10->cur_mode = mode; |
1152 | __v4l2_ctrl_s_ctrl(ctrl: ov08d10->link_freq, val: mode->link_freq_index); |
1153 | pixel_rate = to_rate(link_freq_menu: ov08d10->priv_lane->link_freq_menu, |
1154 | f_index: mode->link_freq_index, |
1155 | nlanes: ov08d10->cur_mode->data_lanes); |
1156 | __v4l2_ctrl_s_ctrl_int64(ctrl: ov08d10->pixel_rate, val: pixel_rate); |
1157 | |
1158 | /* Update limits and set FPS to default */ |
1159 | vblank_def = mode->vts_def - mode->height; |
1160 | __v4l2_ctrl_modify_range(ctrl: ov08d10->vblank, |
1161 | min: mode->vts_min - mode->height, |
1162 | OV08D10_VTS_MAX - mode->height, step: 1, |
1163 | def: vblank_def); |
1164 | __v4l2_ctrl_s_ctrl(ctrl: ov08d10->vblank, val: vblank_def); |
1165 | h_blank = to_pixels_per_line(link_freq_menu: ov08d10->priv_lane->link_freq_menu, |
1166 | hts: mode->hts, |
1167 | f_index: mode->link_freq_index, |
1168 | nlanes: ov08d10->cur_mode->data_lanes) |
1169 | - mode->width; |
1170 | __v4l2_ctrl_modify_range(ctrl: ov08d10->hblank, min: h_blank, max: h_blank, step: 1, |
1171 | def: h_blank); |
1172 | } |
1173 | |
1174 | mutex_unlock(lock: &ov08d10->mutex); |
1175 | |
1176 | return 0; |
1177 | } |
1178 | |
1179 | static int ov08d10_get_format(struct v4l2_subdev *sd, |
1180 | struct v4l2_subdev_state *sd_state, |
1181 | struct v4l2_subdev_format *fmt) |
1182 | { |
1183 | struct ov08d10 *ov08d10 = to_ov08d10(sd); |
1184 | |
1185 | mutex_lock(&ov08d10->mutex); |
1186 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) |
1187 | fmt->format = *v4l2_subdev_state_get_format(sd_state, |
1188 | fmt->pad); |
1189 | else |
1190 | ov08d10_update_pad_format(ov08d10, mode: ov08d10->cur_mode, |
1191 | fmt: &fmt->format); |
1192 | |
1193 | mutex_unlock(lock: &ov08d10->mutex); |
1194 | |
1195 | return 0; |
1196 | } |
1197 | |
1198 | static int ov08d10_enum_mbus_code(struct v4l2_subdev *sd, |
1199 | struct v4l2_subdev_state *sd_state, |
1200 | struct v4l2_subdev_mbus_code_enum *code) |
1201 | { |
1202 | struct ov08d10 *ov08d10 = to_ov08d10(sd); |
1203 | |
1204 | if (code->index > 0) |
1205 | return -EINVAL; |
1206 | |
1207 | mutex_lock(&ov08d10->mutex); |
1208 | code->code = ov08d10_get_format_code(ov08d10); |
1209 | mutex_unlock(lock: &ov08d10->mutex); |
1210 | |
1211 | return 0; |
1212 | } |
1213 | |
1214 | static int ov08d10_enum_frame_size(struct v4l2_subdev *sd, |
1215 | struct v4l2_subdev_state *sd_state, |
1216 | struct v4l2_subdev_frame_size_enum *fse) |
1217 | { |
1218 | struct ov08d10 *ov08d10 = to_ov08d10(sd); |
1219 | |
1220 | if (fse->index >= ov08d10->modes_size) |
1221 | return -EINVAL; |
1222 | |
1223 | mutex_lock(&ov08d10->mutex); |
1224 | if (fse->code != ov08d10_get_format_code(ov08d10)) { |
1225 | mutex_unlock(lock: &ov08d10->mutex); |
1226 | return -EINVAL; |
1227 | } |
1228 | mutex_unlock(lock: &ov08d10->mutex); |
1229 | |
1230 | fse->min_width = ov08d10->priv_lane->sp_modes[fse->index].width; |
1231 | fse->max_width = fse->min_width; |
1232 | fse->min_height = ov08d10->priv_lane->sp_modes[fse->index].height; |
1233 | fse->max_height = fse->min_height; |
1234 | |
1235 | return 0; |
1236 | } |
1237 | |
1238 | static int ov08d10_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) |
1239 | { |
1240 | struct ov08d10 *ov08d10 = to_ov08d10(sd); |
1241 | |
1242 | mutex_lock(&ov08d10->mutex); |
1243 | ov08d10_update_pad_format(ov08d10, mode: &ov08d10->priv_lane->sp_modes[0], |
1244 | v4l2_subdev_state_get_format(fh->state, 0)); |
1245 | mutex_unlock(lock: &ov08d10->mutex); |
1246 | |
1247 | return 0; |
1248 | } |
1249 | |
1250 | static const struct v4l2_subdev_video_ops ov08d10_video_ops = { |
1251 | .s_stream = ov08d10_set_stream, |
1252 | }; |
1253 | |
1254 | static const struct v4l2_subdev_pad_ops ov08d10_pad_ops = { |
1255 | .set_fmt = ov08d10_set_format, |
1256 | .get_fmt = ov08d10_get_format, |
1257 | .enum_mbus_code = ov08d10_enum_mbus_code, |
1258 | .enum_frame_size = ov08d10_enum_frame_size, |
1259 | }; |
1260 | |
1261 | static const struct v4l2_subdev_ops ov08d10_subdev_ops = { |
1262 | .video = &ov08d10_video_ops, |
1263 | .pad = &ov08d10_pad_ops, |
1264 | }; |
1265 | |
1266 | static const struct v4l2_subdev_internal_ops ov08d10_internal_ops = { |
1267 | .open = ov08d10_open, |
1268 | }; |
1269 | |
1270 | static int ov08d10_identify_module(struct ov08d10 *ov08d10) |
1271 | { |
1272 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08d10->sd); |
1273 | u32 val; |
1274 | u16 chip_id; |
1275 | int ret; |
1276 | |
1277 | /* System control registers */ |
1278 | ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, value: 0x00); |
1279 | if (ret < 0) |
1280 | return ret; |
1281 | |
1282 | /* Validate the chip ID */ |
1283 | ret = i2c_smbus_read_byte_data(client, OV08D10_REG_CHIP_ID_0); |
1284 | if (ret < 0) |
1285 | return ret; |
1286 | |
1287 | val = ret << 8; |
1288 | |
1289 | ret = i2c_smbus_read_byte_data(client, OV08D10_REG_CHIP_ID_1); |
1290 | if (ret < 0) |
1291 | return ret; |
1292 | |
1293 | chip_id = val | ret; |
1294 | |
1295 | if ((chip_id & OV08D10_ID_MASK) != OV08D10_CHIP_ID) { |
1296 | dev_err(&client->dev, "unexpected sensor id(0x%04x)\n" , |
1297 | chip_id); |
1298 | return -EINVAL; |
1299 | } |
1300 | |
1301 | return 0; |
1302 | } |
1303 | |
1304 | static int ov08d10_get_hwcfg(struct ov08d10 *ov08d10, struct device *dev) |
1305 | { |
1306 | struct fwnode_handle *ep; |
1307 | struct fwnode_handle *fwnode = dev_fwnode(dev); |
1308 | struct v4l2_fwnode_endpoint bus_cfg = { |
1309 | .bus_type = V4L2_MBUS_CSI2_DPHY |
1310 | }; |
1311 | u32 xvclk_rate; |
1312 | unsigned int i, j; |
1313 | int ret; |
1314 | |
1315 | if (!fwnode) |
1316 | return -ENXIO; |
1317 | |
1318 | ret = fwnode_property_read_u32(fwnode, propname: "clock-frequency" , val: &xvclk_rate); |
1319 | if (ret) |
1320 | return ret; |
1321 | |
1322 | if (xvclk_rate != OV08D10_XVCLK_19_2) |
1323 | dev_warn(dev, "external clock rate %u is unsupported" , |
1324 | xvclk_rate); |
1325 | |
1326 | ep = fwnode_graph_get_next_endpoint(fwnode, NULL); |
1327 | if (!ep) |
1328 | return -ENXIO; |
1329 | |
1330 | ret = v4l2_fwnode_endpoint_alloc_parse(fwnode: ep, vep: &bus_cfg); |
1331 | fwnode_handle_put(fwnode: ep); |
1332 | if (ret) |
1333 | return ret; |
1334 | |
1335 | /* Get number of data lanes */ |
1336 | if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2) { |
1337 | dev_err(dev, "number of CSI2 data lanes %d is not supported" , |
1338 | bus_cfg.bus.mipi_csi2.num_data_lanes); |
1339 | ret = -EINVAL; |
1340 | goto check_hwcfg_error; |
1341 | } |
1342 | |
1343 | dev_dbg(dev, "Using %u data lanes\n" , ov08d10->cur_mode->data_lanes); |
1344 | |
1345 | ov08d10->priv_lane = &lane_cfg_2; |
1346 | ov08d10->modes_size = ov08d10_modes_num(ov08d10); |
1347 | |
1348 | if (!bus_cfg.nr_of_link_frequencies) { |
1349 | dev_err(dev, "no link frequencies defined" ); |
1350 | ret = -EINVAL; |
1351 | goto check_hwcfg_error; |
1352 | } |
1353 | |
1354 | for (i = 0; i < ARRAY_SIZE(ov08d10->priv_lane->link_freq_menu); i++) { |
1355 | for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) { |
1356 | if (ov08d10->priv_lane->link_freq_menu[i] == |
1357 | bus_cfg.link_frequencies[j]) |
1358 | break; |
1359 | } |
1360 | |
1361 | if (j == bus_cfg.nr_of_link_frequencies) { |
1362 | dev_err(dev, "no link frequency %lld supported" , |
1363 | ov08d10->priv_lane->link_freq_menu[i]); |
1364 | ret = -EINVAL; |
1365 | goto check_hwcfg_error; |
1366 | } |
1367 | } |
1368 | |
1369 | check_hwcfg_error: |
1370 | v4l2_fwnode_endpoint_free(vep: &bus_cfg); |
1371 | |
1372 | return ret; |
1373 | } |
1374 | |
1375 | static void ov08d10_remove(struct i2c_client *client) |
1376 | { |
1377 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
1378 | struct ov08d10 *ov08d10 = to_ov08d10(sd); |
1379 | |
1380 | v4l2_async_unregister_subdev(sd); |
1381 | media_entity_cleanup(entity: &sd->entity); |
1382 | v4l2_ctrl_handler_free(hdl: sd->ctrl_handler); |
1383 | pm_runtime_disable(dev: &client->dev); |
1384 | mutex_destroy(lock: &ov08d10->mutex); |
1385 | } |
1386 | |
1387 | static int ov08d10_probe(struct i2c_client *client) |
1388 | { |
1389 | struct ov08d10 *ov08d10; |
1390 | int ret; |
1391 | |
1392 | ov08d10 = devm_kzalloc(dev: &client->dev, size: sizeof(*ov08d10), GFP_KERNEL); |
1393 | if (!ov08d10) |
1394 | return -ENOMEM; |
1395 | |
1396 | ret = ov08d10_get_hwcfg(ov08d10, dev: &client->dev); |
1397 | if (ret) { |
1398 | dev_err(&client->dev, "failed to get HW configuration: %d" , |
1399 | ret); |
1400 | return ret; |
1401 | } |
1402 | |
1403 | v4l2_i2c_subdev_init(sd: &ov08d10->sd, client, ops: &ov08d10_subdev_ops); |
1404 | |
1405 | ret = ov08d10_identify_module(ov08d10); |
1406 | if (ret) { |
1407 | dev_err(&client->dev, "failed to find sensor: %d" , ret); |
1408 | return ret; |
1409 | } |
1410 | |
1411 | mutex_init(&ov08d10->mutex); |
1412 | ov08d10->cur_mode = &ov08d10->priv_lane->sp_modes[0]; |
1413 | ret = ov08d10_init_controls(ov08d10); |
1414 | if (ret) { |
1415 | dev_err(&client->dev, "failed to init controls: %d" , ret); |
1416 | goto probe_error_v4l2_ctrl_handler_free; |
1417 | } |
1418 | |
1419 | ov08d10->sd.internal_ops = &ov08d10_internal_ops; |
1420 | ov08d10->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
1421 | ov08d10->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; |
1422 | ov08d10->pad.flags = MEDIA_PAD_FL_SOURCE; |
1423 | ret = media_entity_pads_init(entity: &ov08d10->sd.entity, num_pads: 1, pads: &ov08d10->pad); |
1424 | if (ret) { |
1425 | dev_err(&client->dev, "failed to init entity pads: %d" , ret); |
1426 | goto probe_error_v4l2_ctrl_handler_free; |
1427 | } |
1428 | |
1429 | ret = v4l2_async_register_subdev_sensor(sd: &ov08d10->sd); |
1430 | if (ret < 0) { |
1431 | dev_err(&client->dev, "failed to register V4L2 subdev: %d" , |
1432 | ret); |
1433 | goto probe_error_media_entity_cleanup; |
1434 | } |
1435 | |
1436 | /* |
1437 | * Device is already turned on by i2c-core with ACPI domain PM. |
1438 | * Enable runtime PM and turn off the device. |
1439 | */ |
1440 | pm_runtime_set_active(dev: &client->dev); |
1441 | pm_runtime_enable(dev: &client->dev); |
1442 | pm_runtime_idle(dev: &client->dev); |
1443 | |
1444 | return 0; |
1445 | |
1446 | probe_error_media_entity_cleanup: |
1447 | media_entity_cleanup(entity: &ov08d10->sd.entity); |
1448 | |
1449 | probe_error_v4l2_ctrl_handler_free: |
1450 | v4l2_ctrl_handler_free(hdl: ov08d10->sd.ctrl_handler); |
1451 | mutex_destroy(lock: &ov08d10->mutex); |
1452 | |
1453 | return ret; |
1454 | } |
1455 | |
1456 | #ifdef CONFIG_ACPI |
1457 | static const struct acpi_device_id ov08d10_acpi_ids[] = { |
1458 | { "OVTI08D1" }, |
1459 | { /* sentinel */ } |
1460 | }; |
1461 | |
1462 | MODULE_DEVICE_TABLE(acpi, ov08d10_acpi_ids); |
1463 | #endif |
1464 | |
1465 | static struct i2c_driver ov08d10_i2c_driver = { |
1466 | .driver = { |
1467 | .name = "ov08d10" , |
1468 | .acpi_match_table = ACPI_PTR(ov08d10_acpi_ids), |
1469 | }, |
1470 | .probe = ov08d10_probe, |
1471 | .remove = ov08d10_remove, |
1472 | }; |
1473 | |
1474 | module_i2c_driver(ov08d10_i2c_driver); |
1475 | |
1476 | MODULE_AUTHOR("Su, Jimmy <jimmy.su@intel.com>" ); |
1477 | MODULE_DESCRIPTION("OmniVision ov08d10 sensor driver" ); |
1478 | MODULE_LICENSE("GPL v2" ); |
1479 | |