1 /*
2  * Copyright 2024 NXP
3  * Copyright (c) 2025, Charles Dias
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #define DT_DRV_COMPAT ovti_ov5640
9 
10 #include <zephyr/kernel.h>
11 #include <math.h>
12 #include <stdlib.h>
13 #include <zephyr/device.h>
14 #include <zephyr/logging/log.h>
15 #include <zephyr/sys/byteorder.h>
16 #include <zephyr/drivers/i2c.h>
17 #include <zephyr/drivers/gpio.h>
18 #include <zephyr/drivers/video.h>
19 #include <zephyr/drivers/video-controls.h>
20 #include <zephyr/dt-bindings/video/video-interfaces.h>
21 
22 LOG_MODULE_REGISTER(video_ov5640, CONFIG_VIDEO_LOG_LEVEL);
23 
24 #define CHIP_ID_REG 0x300a
25 #define CHIP_ID_VAL 0x5640
26 
27 #define SYS_CTRL0_REG     0x3008
28 #define SYS_CTRL0_SW_PWDN 0x42
29 #define SYS_CTRL0_SW_PWUP 0x02
30 #define SYS_CTRL0_SW_RST  0x82
31 
32 #define SYS_RESET00_REG      0x3000
33 #define SYS_RESET02_REG      0x3002
34 #define SYS_CLK_ENABLE00_REG 0x3004
35 #define SYS_CLK_ENABLE02_REG 0x3006
36 #define IO_MIPI_CTRL00_REG   0x300e
37 #define SYSTEM_CONTROL1_REG  0x302e
38 #define SCCB_SYS_CTRL1_REG   0x3103
39 #define TIMING_TC_REG20_REG  0x3820
40 #define TIMING_TC_REG21_REG  0x3821
41 #define HZ5060_CTRL00_REG    0x3c00
42 #define HZ5060_CTRL01_REG    0x3c01
43 #define ISP_CTRL01_REG       0x5001
44 #define PRE_ISP_TEST_SET1    0x503d
45 
46 #define SC_PLL_CTRL0_REG 0x3034
47 #define SC_PLL_CTRL1_REG 0x3035
48 #define SC_PLL_CTRL2_REG 0x3036
49 #define SC_PLL_CTRL3_REG 0x3037
50 #define SYS_ROOT_DIV_REG 0x3108
51 #define PCLK_PERIOD_REG  0x4837
52 
53 #define AEC_PK_REAL_GAIN 0x350a
54 #define AEC_PK_MANUAL    0x3503
55 #define AEC_CTRL00_REG   0x3a00
56 #define AEC_CTRL0F_REG   0x3a0f
57 #define AEC_CTRL10_REG   0x3a10
58 #define AEC_CTRL11_REG   0x3a11
59 #define AEC_CTRL1B_REG   0x3a1b
60 #define AEC_CTRL1E_REG   0x3a1e
61 #define AEC_CTRL1F_REG   0x3a1f
62 
63 #define BLC_CTRL01_REG 0x4001
64 #define BLC_CTRL04_REG 0x4004
65 #define BLC_CTRL05_REG 0x4005
66 
67 #define AWB_CTRL00_REG 0x5180
68 #define AWB_CTRL01_REG 0x5181
69 #define AWB_CTRL02_REG 0x5182
70 #define AWB_CTRL03_REG 0x5183
71 #define AWB_CTRL04_REG 0x5184
72 #define AWB_CTRL05_REG 0x5185
73 #define AWB_CTRL17_REG 0x5191
74 #define AWB_CTRL18_REG 0x5192
75 #define AWB_CTRL19_REG 0x5193
76 #define AWB_CTRL20_REG 0x5194
77 #define AWB_CTRL21_REG 0x5195
78 #define AWB_CTRL22_REG 0x5196
79 #define AWB_CTRL23_REG 0x5197
80 #define AWB_CTRL30_REG 0x519e
81 
82 #define SDE_CTRL0_REG  0x5580
83 #define SDE_CTRL1_REG  0x5581
84 #define SDE_CTRL2_REG  0x5582
85 #define SDE_CTRL3_REG  0x5583
86 #define SDE_CTRL4_REG  0x5584
87 #define SDE_CTRL5_REG  0x5585
88 #define SDE_CTRL6_REG  0x5586
89 #define SDE_CTRL7_REG  0x5587
90 #define SDE_CTRL8_REG  0x5588
91 #define SDE_CTRL9_REG  0x5589
92 #define SDE_CTRL10_REG 0x558a
93 #define SDE_CTRL11_REG 0x558b
94 
95 #define DEFAULT_MIPI_CHANNEL 0
96 
97 #define PI 3.141592654
98 
99 #define ABS(a, b) (a > b ? a - b : b - a)
100 
101 #define PCLK_ROOT_DIV 1
102 #define SCLK2X_DIV    1
103 #define SCLK_DIV      2
104 #define PLL_ROOT_DIV  2
105 #define PLL_PRE_DIV   3
106 #define MIPI_BIT_MODE 0x08
107 
108 /* Must be kept in ascending order */
109 enum ov5640_frame_rate {
110 	OV5640_15_FPS = 15,
111 	OV5640_30_FPS = 30,
112 	OV5640_60_FPS = 60,
113 };
114 
115 struct ov5640_config {
116 	struct i2c_dt_spec i2c;
117 	struct gpio_dt_spec reset_gpio;
118 	struct gpio_dt_spec powerdown_gpio;
119 	int bus_type;
120 };
121 
122 struct ov5640_reg {
123 	uint16_t addr;
124 	uint8_t val;
125 };
126 
127 struct ov5640_mipi_frmrate_config {
128 	uint8_t frmrate;
129 	uint8_t pllCtrl1;
130 	uint8_t pllCtrl2;
131 	uint32_t pixelrate;
132 };
133 
134 struct ov5640_mode_config {
135 	uint16_t width;
136 	uint16_t height;
137 	uint16_t array_size_res_params;
138 	const struct ov5640_reg *res_params;
139 	const struct ov5640_mipi_frmrate_config *mipi_frmrate_config;
140 	uint16_t max_frmrate;
141 	uint16_t def_frmrate;
142 };
143 
144 struct ov5640_data {
145 	struct video_format fmt;
146 	uint64_t cur_pixrate;
147 	uint16_t cur_frmrate;
148 	const struct ov5640_mode_config *cur_mode;
149 };
150 
151 static const struct ov5640_reg init_params_common[] = {
152 	/* Power down */
153 	{SYS_CTRL0_REG, SYS_CTRL0_SW_PWDN},
154 
155 	/* System setting. */
156 	{SCCB_SYS_CTRL1_REG, 0x13},
157 	{SCCB_SYS_CTRL1_REG, 0x03},
158 	{SYS_RESET00_REG, 0x00},
159 	{SYS_CLK_ENABLE00_REG, 0xff},
160 	{SYS_RESET02_REG, 0x1c},
161 	{SYS_CLK_ENABLE02_REG, 0xc3},
162 	{SYSTEM_CONTROL1_REG, 0x08},
163 	{0x3618, 0x00},
164 	{0x3612, 0x29},
165 	{0x3708, 0x64},
166 	{0x3709, 0x52},
167 	{0x370c, 0x03},
168 	{TIMING_TC_REG20_REG, 0x41},
169 	{TIMING_TC_REG21_REG, 0x07},
170 	{0x3630, 0x36},
171 	{0x3631, 0x0e},
172 	{0x3632, 0xe2},
173 	{0x3633, 0x12},
174 	{0x3621, 0xe0},
175 	{0x3704, 0xa0},
176 	{0x3703, 0x5a},
177 	{0x3715, 0x78},
178 	{0x3717, 0x01},
179 	{0x370b, 0x60},
180 	{0x3705, 0x1a},
181 	{0x3905, 0x02},
182 	{0x3906, 0x10},
183 	{0x3901, 0x0a},
184 	{0x3731, 0x12},
185 	{0x3600, 0x08},
186 	{0x3601, 0x33},
187 	{0x302d, 0x60},
188 	{0x3620, 0x52},
189 	{0x371b, 0x20},
190 	{0x471c, 0x50},
191 	{0x3a13, 0x43},
192 	{0x3a18, 0x00},
193 	{0x3a19, 0x7c},
194 	{0x3635, 0x13},
195 	{0x3636, 0x03},
196 	{0x3634, 0x40},
197 	{0x3622, 0x01},
198 	{HZ5060_CTRL01_REG, 0x00},
199 	{AEC_CTRL00_REG, 0x58},
200 	{BLC_CTRL01_REG, 0x02},
201 	{BLC_CTRL04_REG, 0x02},
202 	{BLC_CTRL05_REG, 0x1a},
203 	{ISP_CTRL01_REG, 0xa3},
204 
205 	/* AEC */
206 	{AEC_CTRL0F_REG, 0x30},
207 	{AEC_CTRL10_REG, 0x28},
208 	{AEC_CTRL1B_REG, 0x30},
209 	{AEC_CTRL1E_REG, 0x26},
210 	{AEC_CTRL11_REG, 0x60},
211 	{AEC_CTRL1F_REG, 0x14},
212 
213 	/* AWB */
214 	{AWB_CTRL00_REG, 0xff},
215 	{AWB_CTRL01_REG, 0xf2},
216 	{AWB_CTRL02_REG, 0x00},
217 	{AWB_CTRL03_REG, 0x14},
218 	{AWB_CTRL04_REG, 0x25},
219 	{AWB_CTRL05_REG, 0x24},
220 	{0x5186, 0x09},
221 	{0x5187, 0x09},
222 	{0x5188, 0x09},
223 	{0x5189, 0x88},
224 	{0x518a, 0x54},
225 	{0x518b, 0xee},
226 	{0x518c, 0xb2},
227 	{0x518d, 0x50},
228 	{0x518e, 0x34},
229 	{0x518f, 0x6b},
230 	{0x5190, 0x46},
231 	{AWB_CTRL17_REG, 0xf8},
232 	{AWB_CTRL18_REG, 0x04},
233 	{AWB_CTRL19_REG, 0x70},
234 	{AWB_CTRL20_REG, 0xf0},
235 	{AWB_CTRL21_REG, 0xf0},
236 	{AWB_CTRL22_REG, 0x03},
237 	{AWB_CTRL23_REG, 0x01},
238 	{0x5198, 0x04},
239 	{0x5199, 0x6c},
240 	{0x519a, 0x04},
241 	{0x519b, 0x00},
242 	{0x519c, 0x09},
243 	{0x519d, 0x2b},
244 	{AWB_CTRL30_REG, 0x38},
245 
246 	/* Color Matrix */
247 	{0x5381, 0x1e},
248 	{0x5382, 0x5b},
249 	{0x5383, 0x08},
250 	{0x5384, 0x0a},
251 	{0x5385, 0x7e},
252 	{0x5386, 0x88},
253 	{0x5387, 0x7c},
254 	{0x5388, 0x6c},
255 	{0x5389, 0x10},
256 	{0x538a, 0x01},
257 	{0x538b, 0x98},
258 
259 	/* Sharp */
260 	{0x5300, 0x08},
261 	{0x5301, 0x30},
262 	{0x5302, 0x10},
263 	{0x5303, 0x00},
264 	{0x5304, 0x08},
265 	{0x5305, 0x30},
266 	{0x5306, 0x08},
267 	{0x5307, 0x16},
268 	{0x5309, 0x08},
269 	{0x530a, 0x30},
270 	{0x530b, 0x04},
271 	{0x530c, 0x06},
272 
273 	/* Gamma */
274 	{0x5480, 0x01},
275 	{0x5481, 0x08},
276 	{0x5482, 0x14},
277 	{0x5483, 0x28},
278 	{0x5484, 0x51},
279 	{0x5485, 0x65},
280 	{0x5486, 0x71},
281 	{0x5487, 0x7d},
282 	{0x5488, 0x87},
283 	{0x5489, 0x91},
284 	{0x548a, 0x9a},
285 	{0x548b, 0xaa},
286 	{0x548c, 0xb8},
287 	{0x548d, 0xcd},
288 	{0x548e, 0xdd},
289 	{0x548f, 0xea},
290 	{0x5490, 0x1d},
291 
292 	/* UV adjust. */
293 	{SDE_CTRL0_REG, 0x02},
294 	{SDE_CTRL3_REG, 0x40},
295 	{SDE_CTRL4_REG, 0x10},
296 	{SDE_CTRL9_REG, 0x10},
297 	{SDE_CTRL10_REG, 0x00},
298 	{SDE_CTRL11_REG, 0xf8},
299 
300 	/* Lens correction. */
301 	{0x5800, 0x23},
302 	{0x5801, 0x14},
303 	{0x5802, 0x0f},
304 	{0x5803, 0x0f},
305 	{0x5804, 0x12},
306 	{0x5805, 0x26},
307 	{0x5806, 0x0c},
308 	{0x5807, 0x08},
309 	{0x5808, 0x05},
310 	{0x5809, 0x05},
311 	{0x580a, 0x08},
312 	{0x580b, 0x0d},
313 	{0x580c, 0x08},
314 	{0x580d, 0x03},
315 	{0x580e, 0x00},
316 	{0x580f, 0x00},
317 	{0x5810, 0x03},
318 	{0x5811, 0x09},
319 	{0x5812, 0x07},
320 	{0x5813, 0x03},
321 	{0x5814, 0x00},
322 	{0x5815, 0x01},
323 	{0x5816, 0x03},
324 	{0x5817, 0x08},
325 	{0x5818, 0x0d},
326 	{0x5819, 0x08},
327 	{0x581a, 0x05},
328 	{0x581b, 0x06},
329 	{0x581c, 0x08},
330 	{0x581d, 0x0e},
331 	{0x581e, 0x29},
332 	{0x581f, 0x17},
333 	{0x5820, 0x11},
334 	{0x5821, 0x11},
335 	{0x5822, 0x15},
336 	{0x5823, 0x28},
337 	{0x5824, 0x46},
338 	{0x5825, 0x26},
339 	{0x5826, 0x08},
340 	{0x5827, 0x26},
341 	{0x5828, 0x64},
342 	{0x5829, 0x26},
343 	{0x582a, 0x24},
344 	{0x582b, 0x22},
345 	{0x582c, 0x24},
346 	{0x582d, 0x24},
347 	{0x582e, 0x06},
348 	{0x582f, 0x22},
349 	{0x5830, 0x40},
350 	{0x5831, 0x42},
351 	{0x5832, 0x24},
352 	{0x5833, 0x26},
353 	{0x5834, 0x24},
354 	{0x5835, 0x22},
355 	{0x5836, 0x22},
356 	{0x5837, 0x26},
357 	{0x5838, 0x44},
358 	{0x5839, 0x24},
359 	{0x583a, 0x26},
360 	{0x583b, 0x28},
361 	{0x583c, 0x42},
362 	{0x583d, 0xce},
363 	{0x5000, 0xa7},
364 };
365 
366 static const struct ov5640_reg init_params_dvp[] = {
367 	{0x4740, 0x21},
368 	{0x4050, 0x6e},
369 	{0x4051, 0x8f},
370 	{0x3017, 0xff},
371 	{0x3018, 0xff},
372 	{0x302c, 0x02},
373 	{0x3108, 0x01},
374 	{0x3630, 0x2e},
375 	{0x3a18, 0x00},
376 	{0x3a19, 0xf8},
377 	{0x3635, 0x1c},
378 	{0x3c04, 0x28},
379 	{0x3c05, 0x98},
380 	{0x3c06, 0x00},
381 	{0x3c07, 0x08},
382 	{0x3c08, 0x00},
383 	{0x3c09, 0x1c},
384 	{0x3c0a, 0x9c},
385 	{0x3c0b, 0x40},
386 	{TIMING_TC_REG20_REG, 0x47},
387 	{TIMING_TC_REG21_REG, 0x01},
388 	{0x3800, 0x00},
389 	{0x3801, 0x00},
390 	{0x3802, 0x00},
391 	{0x3803, 0x04},
392 	{0x3804, 0x0a},
393 	{0x3805, 0x3f},
394 	{0x3806, 0x07},
395 	{0x3807, 0x9b},
396 	{0x3808, 0x05},
397 	{0x3809, 0x00},
398 	{0x380a, 0x03},
399 	{0x380b, 0xc0},
400 	{0x3810, 0x00},
401 	{0x3811, 0x10},
402 	{0x3812, 0x00},
403 	{0x3813, 0x06},
404 	{0x3814, 0x31},
405 	{0x3815, 0x31},
406 	{0x3034, 0x1a},
407 	{0x3035, 0x11},
408 	{0x3036, 0x64},
409 	{0x3037, 0x13},
410 	{0x3038, 0x00},
411 	{0x3039, 0x00},
412 	{0x380c, 0x07},
413 	{0x380d, 0x68},
414 	{0x380e, 0x03},
415 	{0x380f, 0xd8},
416 	{0x3c01, 0xb4},
417 	{0x3c00, 0x04},
418 	{0x3a08, 0x00},
419 	{0x3a09, 0x93},
420 	{0x3a0e, 0x06},
421 	{0x3a0a, 0x00},
422 	{0x3a0b, 0x7b},
423 	{0x3a0d, 0x08},
424 	{0x3a00, 0x38},
425 	{0x3a02, 0x05},
426 	{0x3a03, 0xc4},
427 	{0x3a14, 0x05},
428 	{0x3a15, 0xc4},
429 	{0x300e, 0x58},
430 	{0x302e, 0x00},
431 	{0x4300, 0x30},
432 	{0x501f, 0x00},
433 	{0x4713, 0x04},
434 	{0x4407, 0x04},
435 	{0x460b, 0x35},
436 	{0x460c, 0x22},
437 	{0x3824, 0x02},
438 	{0x3406, 0x01},
439 	{0x3400, 0x06},
440 	{0x3401, 0x80},
441 	{0x3402, 0x04},
442 	{0x3403, 0x00},
443 	{0x3404, 0x06},
444 	{0x3405, 0x00},
445 	{0x5688, 0x22},
446 	{0x5689, 0x22},
447 	{0x568a, 0x42},
448 	{0x568b, 0x24},
449 	{0x568c, 0x42},
450 	{0x568d, 0x24},
451 	{0x568e, 0x22},
452 	{0x568f, 0x22},
453 	{0x5025, 0x00},
454 	{0x3406, 0x00},
455 	{0x3503, 0x00},
456 	{0x3008, 0x02},
457 	{0x3a02, 0x07},
458 	{0x3a03, 0xae},
459 	{0x3a08, 0x01},
460 	{0x3a09, 0x27},
461 	{0x3a0a, 0x00},
462 	{0x3a0b, 0xf6},
463 	{0x3a0e, 0x06},
464 	{0x3a0d, 0x08},
465 	{0x3a14, 0x07},
466 	{0x3a15, 0xae},
467 };
468 
469 static const struct ov5640_reg csi2_low_res_params[] = {
470 	{0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, {0x3803, 0x04}, {0x3804, 0x0a},
471 	{0x3805, 0x3f}, {0x3806, 0x07}, {0x3807, 0x9b}, {0x3808, 0x02}, {0x3809, 0x80},
472 	{0x380a, 0x01}, {0x380b, 0xe0}, {0x380c, 0x07}, {0x380d, 0x68}, {0x380e, 0x03},
473 	{0x380f, 0xd8}, {0x3810, 0x00}, {0x3811, 0x10}, {0x3812, 0x00}, {0x3813, 0x06},
474 	{0x3814, 0x31}, {0x3815, 0x31}, {0x3824, 0x02}, {0x460c, 0x22}};
475 
476 static const struct ov5640_reg csi2_hd_res_params[] = {
477 	{0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, {0x3803, 0xfa}, {0x3804, 0x0a},
478 	{0x3805, 0x3f}, {0x3806, 0x06}, {0x3807, 0xa9}, {0x3808, 0x05}, {0x3809, 0x00},
479 	{0x380a, 0x02}, {0x380b, 0xd0}, {0x380c, 0x07}, {0x380d, 0x64}, {0x380e, 0x02},
480 	{0x380f, 0xe4}, {0x3810, 0x00}, {0x3811, 0x10}, {0x3812, 0x00}, {0x3813, 0x04},
481 	{0x3814, 0x31}, {0x3815, 0x31}, {0x3824, 0x04}, {0x460c, 0x20}};
482 
483 static const struct ov5640_mipi_frmrate_config mipi_hd_frmrate_params[] = {
484 	{15, 0x21, 0x2A, 24000000}, {30, 0x21, 0x54, 48000000}, {60, 0x11, 0x54, 96000000}};
485 
486 static const struct ov5640_mipi_frmrate_config mipi_vga_frmrate_params[] = {
487 	{15, 0x22, 0x38, 24000000}, {30, 0x14, 0x38, 24000000}, {60, 0x14, 0x70, 48000000}};
488 
489 static const struct ov5640_mode_config csi2_modes[] = {
490 	{
491 		.width = 640,
492 		.height = 480,
493 		.array_size_res_params = ARRAY_SIZE(csi2_low_res_params),
494 		.res_params = csi2_low_res_params,
495 		.mipi_frmrate_config = mipi_vga_frmrate_params,
496 		.max_frmrate = OV5640_60_FPS,
497 		.def_frmrate = OV5640_30_FPS,
498 	},
499 	{
500 		.width = 1280,
501 		.height = 720,
502 		.array_size_res_params = ARRAY_SIZE(csi2_hd_res_params),
503 		.res_params = csi2_hd_res_params,
504 		.mipi_frmrate_config = mipi_hd_frmrate_params,
505 		.max_frmrate = OV5640_60_FPS,
506 		.def_frmrate = OV5640_30_FPS,
507 	}};
508 
509 static const int ov5640_frame_rates[] = {OV5640_15_FPS, OV5640_30_FPS, OV5640_60_FPS};
510 
511 /* Initialization sequence for QQVGA resolution (160x120) */
512 static const struct ov5640_reg dvp_160x120_res_params[] = {
513 	{0x3800, 0x00}, {0x3801, 0x08}, {0x3802, 0x00}, {0x3803, 0x02}, {0x3804, 0x0a},
514 	{0x3805, 0x37}, {0x3806, 0x07}, {0x3807, 0xa1}, {0x3808, 0x00}, {0x3809, 0xa0},
515 	{0x380a, 0x00}, {0x380b, 0x78}, {0x380c, 0x06}, {0x380d, 0x14}, {0x380e, 0x03},
516 	{0x380f, 0xe8}, {0x3810, 0x00}, {0x3811, 0x04}, {0x3812, 0x00}, {0x3813, 0x02},
517 	{0x3814, 0x31}, {0x3815, 0x31}, {0x3820, 0x47}, {0x3821, 0x01}, {0x4602, 0x00},
518 	{0x4603, 0xa0}, {0x4604, 0x00}, {0x4605, 0x78}};
519 
520 /* Initialization sequence for QVGA resolution (320x240) */
521 static const struct ov5640_reg dvp_320x240_res_params[] = {
522 	{0x3800, 0x00}, {0x3801, 0x08}, {0x3802, 0x00}, {0x3803, 0x02}, {0x3804, 0x0a},
523 	{0x3805, 0x37}, {0x3806, 0x07}, {0x3807, 0xa1}, {0x3808, 0x01}, {0x3809, 0x40},
524 	{0x380a, 0x00}, {0x380b, 0xf0}, {0x380c, 0x06}, {0x380d, 0x14}, {0x380e, 0x03},
525 	{0x380f, 0xe8}, {0x3810, 0x00}, {0x3811, 0x04}, {0x3812, 0x00}, {0x3813, 0x02},
526 	{0x3814, 0x31}, {0x3815, 0x31}, {0x3820, 0x47}, {0x3821, 0x01}, {0x4602, 0x01},
527 	{0x4603, 0x40}, {0x4604, 0x00}, {0x4605, 0xf0}};
528 
529 /* Initialization sequence for WQVGA resolution (480x272) */
530 static const struct ov5640_reg dvp_480x272_res_params[] = {
531 	{0x3800, 0x00}, {0x3801, 0x08}, {0x3802, 0x00}, {0x3803, 0x02}, {0x3804, 0x0a},
532 	{0x3805, 0x37}, {0x3806, 0x07}, {0x3807, 0xa1}, {0x3808, 0x01}, {0x3809, 0xe0},
533 	{0x380a, 0x01}, {0x380b, 0x10}, {0x380c, 0x06}, {0x380d, 0x14}, {0x380e, 0x03},
534 	{0x380f, 0xe8}, {0x3810, 0x00}, {0x3811, 0x04}, {0x3812, 0x00}, {0x3813, 0x79},
535 	{0x3814, 0x31}, {0x3815, 0x31}, {0x3820, 0x47}, {0x3821, 0x01}, {0x4602, 0x01},
536 	{0x4603, 0xe0}, {0x4604, 0x01}, {0x4605, 0x10}};
537 
538 static const struct ov5640_mode_config dvp_modes[] = {
539 	{
540 		.width = 160,
541 		.height = 120,
542 		.array_size_res_params = ARRAY_SIZE(dvp_160x120_res_params),
543 		.res_params = dvp_160x120_res_params,
544 		.max_frmrate = OV5640_60_FPS,
545 		.def_frmrate = OV5640_30_FPS,
546 	},
547 	{
548 		.width = 320,
549 		.height = 240,
550 		.array_size_res_params = ARRAY_SIZE(dvp_320x240_res_params),
551 		.res_params = dvp_320x240_res_params,
552 		.max_frmrate = OV5640_60_FPS,
553 		.def_frmrate = OV5640_30_FPS,
554 	},
555 	{
556 		.width = 480,
557 		.height = 272,
558 		.array_size_res_params = ARRAY_SIZE(dvp_480x272_res_params),
559 		.res_params = dvp_480x272_res_params,
560 		.max_frmrate = OV5640_60_FPS,
561 		.def_frmrate = OV5640_30_FPS,
562 	}};
563 
564 #define OV5640_VIDEO_FORMAT_CAP(width, height, format)                                             \
565 	{.pixelformat = (format),                                                                  \
566 	 .width_min = (width),                                                                     \
567 	 .width_max = (width),                                                                     \
568 	 .height_min = (height),                                                                   \
569 	 .height_max = (height),                                                                   \
570 	 .width_step = 0,                                                                          \
571 	 .height_step = 0}
572 
573 static const struct video_format_cap csi2_fmts[] = {
574 	OV5640_VIDEO_FORMAT_CAP(1280, 720, VIDEO_PIX_FMT_RGB565),
575 	OV5640_VIDEO_FORMAT_CAP(1280, 720, VIDEO_PIX_FMT_YUYV),
576 	OV5640_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_RGB565),
577 	OV5640_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_YUYV),
578 	{0}};
579 
580 static const struct video_format_cap dvp_fmts[] = {
581 	OV5640_VIDEO_FORMAT_CAP(160, 120, VIDEO_PIX_FMT_RGB565),
582 	OV5640_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_RGB565),
583 	OV5640_VIDEO_FORMAT_CAP(480, 272, VIDEO_PIX_FMT_RGB565),
584 	{0}};
585 
ov5640_is_dvp(const struct device * dev)586 static inline bool ov5640_is_dvp(const struct device *dev)
587 {
588 	const struct ov5640_config *cfg = dev->config;
589 
590 	return cfg->bus_type == VIDEO_BUS_TYPE_PARALLEL;
591 }
592 
ov5640_read_reg(const struct i2c_dt_spec * spec,const uint16_t addr,void * val,const uint8_t val_size)593 static int ov5640_read_reg(const struct i2c_dt_spec *spec, const uint16_t addr, void *val,
594 			   const uint8_t val_size)
595 {
596 	int ret;
597 	struct i2c_msg msg[2];
598 	uint8_t addr_buf[2];
599 
600 	if (val_size > 4) {
601 		return -ENOTSUP;
602 	}
603 
604 	addr_buf[1] = addr & 0xFF;
605 	addr_buf[0] = addr >> 8;
606 	msg[0].buf = addr_buf;
607 	msg[0].len = 2U;
608 	msg[0].flags = I2C_MSG_WRITE;
609 
610 	msg[1].buf = (uint8_t *)val;
611 	msg[1].len = val_size;
612 	msg[1].flags = I2C_MSG_READ | I2C_MSG_STOP | I2C_MSG_RESTART;
613 
614 	ret = i2c_transfer_dt(spec, msg, 2);
615 	if (ret) {
616 		return ret;
617 	}
618 
619 	switch (val_size) {
620 	case 4:
621 		*(uint32_t *)val = sys_be32_to_cpu(*(uint32_t *)val);
622 		break;
623 	case 2:
624 		*(uint16_t *)val = sys_be16_to_cpu(*(uint16_t *)val);
625 		break;
626 	case 1:
627 		break;
628 	default:
629 		return -ENOTSUP;
630 	}
631 
632 	return 0;
633 }
634 
ov5640_write_reg(const struct i2c_dt_spec * spec,const uint16_t addr,const uint8_t val)635 static int ov5640_write_reg(const struct i2c_dt_spec *spec, const uint16_t addr, const uint8_t val)
636 {
637 	uint8_t addr_buf[2];
638 	struct i2c_msg msg[2];
639 
640 	addr_buf[1] = addr & 0xFF;
641 	addr_buf[0] = addr >> 8;
642 	msg[0].buf = addr_buf;
643 	msg[0].len = 2U;
644 	msg[0].flags = I2C_MSG_WRITE;
645 
646 	msg[1].buf = (uint8_t *)&val;
647 	msg[1].len = 1;
648 	msg[1].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
649 
650 	return i2c_transfer_dt(spec, msg, 2);
651 }
652 
ov5640_modify_reg(const struct i2c_dt_spec * spec,const uint16_t addr,const uint8_t mask,const uint8_t val)653 static int ov5640_modify_reg(const struct i2c_dt_spec *spec, const uint16_t addr,
654 			     const uint8_t mask, const uint8_t val)
655 {
656 	uint8_t regVal = 0;
657 	int ret = ov5640_read_reg(spec, addr, &regVal, sizeof(regVal));
658 
659 	if (ret) {
660 		return ret;
661 	}
662 
663 	return ov5640_write_reg(spec, addr, (regVal & ~mask) | (val & mask));
664 }
665 
ov5640_write_multi_regs(const struct i2c_dt_spec * spec,const struct ov5640_reg * regs,const uint32_t num_regs)666 static int ov5640_write_multi_regs(const struct i2c_dt_spec *spec, const struct ov5640_reg *regs,
667 				   const uint32_t num_regs)
668 {
669 	int ret;
670 
671 	for (int i = 0; i < num_regs; i++) {
672 		ret = ov5640_write_reg(spec, regs[i].addr, regs[i].val);
673 		if (ret) {
674 			return ret;
675 		}
676 	}
677 
678 	return 0;
679 }
680 
ov5640_set_fmt_dvp(const struct ov5640_config * cfg)681 static int ov5640_set_fmt_dvp(const struct ov5640_config *cfg)
682 {
683 	int ret = 0;
684 
685 	ret = ov5640_modify_reg(&cfg->i2c, TIMING_TC_REG21_REG, 0x20, 0x00);
686 
687 	if (ret) {
688 		LOG_ERR("Unable to configure REG: %d on DVP", TIMING_TC_REG21_REG);
689 		return ret;
690 	}
691 
692 	ret = ov5640_modify_reg(&cfg->i2c, SYS_RESET02_REG, 0x1C, 0x1C);
693 
694 	if (ret) {
695 		LOG_ERR("Unable to configure REG: %d on DVP", SYS_RESET02_REG);
696 		return ret;
697 	}
698 
699 	ret = ov5640_modify_reg(&cfg->i2c, SYS_CLK_ENABLE02_REG, 0x28, 0x00);
700 
701 	if (ret) {
702 		LOG_ERR("Unable to configure REG: %d on DVP", SYS_CLK_ENABLE02_REG);
703 		return ret;
704 	}
705 
706 	return 0;
707 }
708 
ov5640_set_frmival(const struct device * dev,enum video_endpoint_id ep,struct video_frmival * frmival)709 static int ov5640_set_frmival(const struct device *dev, enum video_endpoint_id ep,
710 			      struct video_frmival *frmival)
711 {
712 	const struct ov5640_config *cfg = dev->config;
713 	struct ov5640_data *drv_data = dev->data;
714 	int ret;
715 	uint8_t i, ind = 0;
716 	uint32_t desired_frmrate, best_match = ov5640_frame_rates[ind];
717 
718 	if (ov5640_is_dvp(dev)) {
719 		return -ENOTSUP;
720 	}
721 
722 	desired_frmrate = DIV_ROUND_CLOSEST(frmival->denominator, frmival->numerator);
723 
724 	/* Find the supported frame rate closest to the desired one */
725 	for (i = 0; i < ARRAY_SIZE(ov5640_frame_rates); i++) {
726 		if (ov5640_frame_rates[i] <= drv_data->cur_mode->max_frmrate &&
727 		    ABS(desired_frmrate, ov5640_frame_rates[i]) <
728 			    ABS(desired_frmrate, best_match)) {
729 			best_match = ov5640_frame_rates[i];
730 			ind = i;
731 		}
732 	}
733 
734 	struct ov5640_reg frmrate_params[] = {
735 		{SC_PLL_CTRL1_REG, drv_data->cur_mode->mipi_frmrate_config[ind].pllCtrl1},
736 		{SC_PLL_CTRL2_REG, drv_data->cur_mode->mipi_frmrate_config[ind].pllCtrl2},
737 		{PCLK_PERIOD_REG, 0x0a}};
738 
739 	ret = ov5640_write_multi_regs(&cfg->i2c, frmrate_params, ARRAY_SIZE(frmrate_params));
740 	ret |= ov5640_modify_reg(&cfg->i2c, SC_PLL_CTRL0_REG, 0x0f, MIPI_BIT_MODE);
741 	ret |= ov5640_modify_reg(&cfg->i2c, SC_PLL_CTRL3_REG, 0x1f,
742 				 (LOG2CEIL(PLL_ROOT_DIV) << 4) | (PLL_PRE_DIV & 0x07));
743 	ret |= ov5640_modify_reg(&cfg->i2c, SYS_ROOT_DIV_REG, 0x3f,
744 				 (LOG2CEIL(PCLK_ROOT_DIV) & 0x03 << 4) |
745 					 (LOG2CEIL(SCLK2X_DIV) & 0x03 << 2) |
746 					 (LOG2CEIL(SCLK_DIV) & 0x03));
747 
748 	if (ret) {
749 		LOG_ERR("Unable to set frame interval");
750 		return ret;
751 	}
752 
753 	drv_data->cur_frmrate = best_match;
754 	drv_data->cur_pixrate = drv_data->cur_mode->mipi_frmrate_config[ind].pixelrate;
755 
756 	frmival->numerator = 1;
757 	frmival->denominator = best_match;
758 
759 	return 0;
760 }
761 
ov5640_set_fmt(const struct device * dev,enum video_endpoint_id ep,struct video_format * fmt)762 static int ov5640_set_fmt(const struct device *dev, enum video_endpoint_id ep,
763 			  struct video_format *fmt)
764 {
765 	struct ov5640_data *drv_data = dev->data;
766 	const struct ov5640_config *cfg = dev->config;
767 	int ret, i;
768 	struct video_frmival def_frmival;
769 	const struct video_format_cap *fmts;
770 	const struct ov5640_mode_config *modes;
771 	size_t num_fmts;
772 	size_t array_size_modes;
773 
774 	if (ov5640_is_dvp(dev)) {
775 		fmts = dvp_fmts;
776 		modes = dvp_modes;
777 		num_fmts = ARRAY_SIZE(dvp_fmts);
778 		array_size_modes = ARRAY_SIZE(dvp_modes);
779 	} else {
780 		fmts = csi2_fmts;
781 		modes = csi2_modes;
782 		num_fmts = ARRAY_SIZE(csi2_fmts);
783 		array_size_modes = ARRAY_SIZE(csi2_modes);
784 	}
785 
786 	for (i = 0; i < num_fmts; ++i) {
787 		if (fmt->pixelformat == fmts[i].pixelformat && fmt->width >= fmts[i].width_min &&
788 		    fmt->width <= fmts[i].width_max && fmt->height >= fmts[i].height_min &&
789 		    fmt->height <= fmts[i].height_max) {
790 			break;
791 		}
792 	}
793 
794 	if (i == num_fmts) {
795 		LOG_ERR("Unsupported pixel format or resolution");
796 		return -ENOTSUP;
797 	}
798 
799 	if (!memcmp(&drv_data->fmt, fmt, sizeof(drv_data->fmt))) {
800 		return 0;
801 	}
802 
803 	drv_data->fmt = *fmt;
804 
805 	/* Set resolution */
806 	for (i = 0; i < array_size_modes; i++) {
807 		if (fmt->width == modes[i].width && fmt->height == modes[i].height) {
808 			ret = ov5640_write_multi_regs(&cfg->i2c, modes[i].res_params,
809 						      modes[i].array_size_res_params);
810 			if (ret) {
811 				LOG_ERR("Unable to set resolution parameters");
812 				return ret;
813 			}
814 
815 			drv_data->cur_mode = &modes[i];
816 			break;
817 		}
818 	}
819 
820 	/* Set pixel format */
821 	struct ov5640_reg fmt_params[] = {
822 		{0x4300, 0x6f},
823 		{0x501f, 0x01},
824 	};
825 
826 	if (fmt->pixelformat == VIDEO_PIX_FMT_YUYV) {
827 		fmt_params[0].val = 0x3f;
828 		fmt_params[1].val = 0x00;
829 	}
830 
831 	ret = ov5640_write_multi_regs(&cfg->i2c, fmt_params, ARRAY_SIZE(fmt_params));
832 	if (ret) {
833 		LOG_ERR("Unable to set pixel format");
834 		return ret;
835 	}
836 
837 	if (ov5640_is_dvp(dev)) {
838 		return ov5640_set_fmt_dvp(cfg);
839 	}
840 
841 	/* Set frame rate */
842 	def_frmival.denominator = drv_data->cur_mode->def_frmrate;
843 	def_frmival.numerator = 1;
844 
845 	return ov5640_set_frmival(dev, ep, &def_frmival);
846 }
847 
ov5640_get_fmt(const struct device * dev,enum video_endpoint_id ep,struct video_format * fmt)848 static int ov5640_get_fmt(const struct device *dev, enum video_endpoint_id ep,
849 			  struct video_format *fmt)
850 {
851 	struct ov5640_data *drv_data = dev->data;
852 
853 	*fmt = drv_data->fmt;
854 
855 	return 0;
856 }
857 
ov5640_get_caps(const struct device * dev,enum video_endpoint_id ep,struct video_caps * caps)858 static int ov5640_get_caps(const struct device *dev, enum video_endpoint_id ep,
859 			   struct video_caps *caps)
860 {
861 	caps->format_caps = ov5640_is_dvp(dev) ? dvp_fmts : csi2_fmts;
862 	return 0;
863 }
864 
ov5640_set_stream(const struct device * dev,bool enable)865 static int ov5640_set_stream(const struct device *dev, bool enable)
866 {
867 	const struct ov5640_config *cfg = dev->config;
868 
869 	if (!ov5640_is_dvp(dev)) {
870 		/* Power up / down MIPI PHY HS Tx & LP Rx in 2 data lanes mode */
871 		int ret = ov5640_write_reg(&cfg->i2c, IO_MIPI_CTRL00_REG, enable ? 0x45 : 0x40);
872 		if (ret) {
873 			LOG_ERR("Unable to power up / down MIPI PHY");
874 			return ret;
875 		}
876 	}
877 
878 	return ov5640_write_reg(&cfg->i2c, SYS_CTRL0_REG,
879 				enable ? SYS_CTRL0_SW_PWUP : SYS_CTRL0_SW_PWDN);
880 }
881 
882 #define TEST_PATTERN_ENABLE  BIT(7)
883 #define TEST_PATTERN_ROLLING BIT(6)
884 #define TEST_PATTERN_BAR     (0 << 0)
885 #define TEST_PATTERN_SQUARE  (2 << 0)
886 
887 static const uint8_t test_pattern_val[] = {
888 	0,
889 	TEST_PATTERN_ENABLE | TEST_PATTERN_BAR | (1 << 2),
890 	TEST_PATTERN_ENABLE | TEST_PATTERN_BAR | (1 << 2) | TEST_PATTERN_ROLLING,
891 	TEST_PATTERN_ENABLE | TEST_PATTERN_SQUARE,
892 	TEST_PATTERN_ENABLE | TEST_PATTERN_SQUARE | TEST_PATTERN_ROLLING,
893 };
894 
ov5640_set_ctrl_test_pattern(const struct device * dev,int value)895 static int ov5640_set_ctrl_test_pattern(const struct device *dev, int value)
896 {
897 	const struct ov5640_config *cfg = dev->config;
898 
899 	if (!IN_RANGE(value, 0, ARRAY_SIZE(test_pattern_val) - 1)) {
900 		return -EINVAL;
901 	}
902 
903 	return ov5640_write_reg(&cfg->i2c, PRE_ISP_TEST_SET1, test_pattern_val[value]);
904 }
905 
ov5640_set_ctrl_hue(const struct device * dev,int value)906 static int ov5640_set_ctrl_hue(const struct device *dev, int value)
907 {
908 	const struct ov5640_config *cfg = dev->config;
909 	int cos_coef, sin_coef, sign = 0;
910 
911 	if (!IN_RANGE(value, 0, 360)) {
912 		return -EINVAL;
913 	}
914 
915 	double rad_val = value;
916 	int ret = ov5640_modify_reg(&cfg->i2c, SDE_CTRL0_REG, BIT(0), BIT(0));
917 
918 	if (ret) {
919 		return ret;
920 	}
921 
922 	rad_val = value * PI / 180.0;
923 	cos_coef = round(cos(rad_val) * 128);
924 	sin_coef = round(sin(rad_val) * 128);
925 
926 	if (0 <= value && value < 90) {
927 		sign = 0x01;
928 	} else if (90 <= value && value < 180) {
929 		sign = 0x31;
930 	} else if (180 <= value && value < 270) {
931 		sign = 0x32;
932 	} else if (270 <= value && value < 360) {
933 		sign = 0x02;
934 	}
935 
936 	struct ov5640_reg hue_params[] = {{SDE_CTRL8_REG, sign},
937 					  {SDE_CTRL1_REG, abs(cos_coef)},
938 					  {SDE_CTRL2_REG, abs(sin_coef)}};
939 
940 	return ov5640_write_multi_regs(&cfg->i2c, hue_params, ARRAY_SIZE(hue_params));
941 }
942 
ov5640_set_ctrl_saturation(const struct device * dev,int value)943 static int ov5640_set_ctrl_saturation(const struct device *dev, int value)
944 {
945 	const struct ov5640_config *cfg = dev->config;
946 
947 	if (!IN_RANGE(value, 0, UINT8_MAX)) {
948 		return -EINVAL;
949 	}
950 
951 	struct ov5640_reg saturation_params[] = {{SDE_CTRL3_REG, value}, {SDE_CTRL4_REG, value}};
952 	int ret = ov5640_modify_reg(&cfg->i2c, SDE_CTRL8_REG, BIT(6) | BIT(0), BIT(6) | BIT(0));
953 
954 	if (ret) {
955 		return ret;
956 	}
957 
958 	return ov5640_write_multi_regs(&cfg->i2c, saturation_params, ARRAY_SIZE(saturation_params));
959 }
960 
ov5640_set_ctrl_brightness(const struct device * dev,int value)961 static int ov5640_set_ctrl_brightness(const struct device *dev, int value)
962 {
963 	const struct ov5640_config *cfg = dev->config;
964 
965 	if (!IN_RANGE(value, -UINT8_MAX, UINT8_MAX)) {
966 		return -EINVAL;
967 	}
968 
969 	struct ov5640_reg brightness_params[] = {{SDE_CTRL8_REG, value >= 0 ? 0x01 : 0x09},
970 						 {SDE_CTRL7_REG, abs(value) & 0xff}};
971 	int ret = ov5640_modify_reg(&cfg->i2c, SDE_CTRL0_REG, BIT(2), BIT(2));
972 
973 	if (ret) {
974 		return ret;
975 	}
976 
977 	return ov5640_write_multi_regs(&cfg->i2c, brightness_params, ARRAY_SIZE(brightness_params));
978 }
979 
ov5640_set_ctrl_contrast(const struct device * dev,int value)980 static int ov5640_set_ctrl_contrast(const struct device *dev, int value)
981 {
982 	const struct ov5640_config *cfg = dev->config;
983 
984 	if (!IN_RANGE(value, 0, UINT8_MAX)) {
985 		return -EINVAL;
986 	}
987 
988 	int ret = ov5640_modify_reg(&cfg->i2c, SDE_CTRL0_REG, BIT(2), BIT(2));
989 
990 	if (ret) {
991 		return ret;
992 	}
993 
994 	return ov5640_write_reg(&cfg->i2c, SDE_CTRL6_REG, value & 0xff);
995 }
996 
ov5640_set_ctrl_gain(const struct device * dev,int value)997 static int ov5640_set_ctrl_gain(const struct device *dev, int value)
998 {
999 	const struct ov5640_config *cfg = dev->config;
1000 
1001 	if (!IN_RANGE(value, 0, UINT16_MAX)) {
1002 		return -EINVAL;
1003 	}
1004 
1005 	if (value) {
1006 		int ret = ov5640_modify_reg(&cfg->i2c, AEC_PK_MANUAL, BIT(1), BIT(0));
1007 
1008 		if (ret) {
1009 			return ret;
1010 		}
1011 
1012 		struct ov5640_reg gain_params[] = {{AEC_PK_REAL_GAIN, value >> 8},
1013 						   {AEC_PK_REAL_GAIN + 1, value & 0xff}};
1014 
1015 		return ov5640_write_multi_regs(&cfg->i2c, gain_params, ARRAY_SIZE(gain_params));
1016 	} else {
1017 		return ov5640_write_reg(&cfg->i2c, AEC_PK_MANUAL, 0);
1018 	}
1019 }
1020 
ov5640_set_ctrl_hflip(const struct device * dev,int value)1021 static int ov5640_set_ctrl_hflip(const struct device *dev, int value)
1022 {
1023 	const struct ov5640_config *cfg = dev->config;
1024 
1025 	return ov5640_modify_reg(&cfg->i2c, TIMING_TC_REG21_REG, BIT(2) | BIT(1),
1026 				 value ? 0 : BIT(2) | BIT(1));
1027 }
1028 
ov5640_set_ctrl_vflip(const struct device * dev,int value)1029 static int ov5640_set_ctrl_vflip(const struct device *dev, int value)
1030 {
1031 	const struct ov5640_config *cfg = dev->config;
1032 
1033 	return ov5640_modify_reg(&cfg->i2c, TIMING_TC_REG20_REG, BIT(2) | BIT(1),
1034 				 value ? BIT(2) | BIT(1) : 0);
1035 }
1036 
ov5640_set_ctrl_power_line_freq(const struct device * dev,int value)1037 static int ov5640_set_ctrl_power_line_freq(const struct device *dev, int value)
1038 {
1039 	const struct ov5640_config *cfg = dev->config;
1040 	int ret;
1041 
1042 	switch (value) {
1043 	case VIDEO_CID_POWER_LINE_FREQUENCY_AUTO:
1044 		ret = ov5640_modify_reg(&cfg->i2c, HZ5060_CTRL01_REG, BIT(7), 0);
1045 		return ret;
1046 	case VIDEO_CID_POWER_LINE_FREQUENCY_50HZ:
1047 		ret = ov5640_modify_reg(&cfg->i2c, HZ5060_CTRL00_REG, BIT(2), BIT(2));
1048 		break;
1049 	case VIDEO_CID_POWER_LINE_FREQUENCY_60HZ:
1050 		ret = ov5640_modify_reg(&cfg->i2c, HZ5060_CTRL00_REG, BIT(2), 0);
1051 		break;
1052 	default:
1053 		return -EINVAL;
1054 	}
1055 
1056 	if (ret) {
1057 		return ret;
1058 	}
1059 
1060 	return ov5640_modify_reg(&cfg->i2c, HZ5060_CTRL01_REG, BIT(7), BIT(7));
1061 }
1062 
ov5640_set_ctrl(const struct device * dev,unsigned int cid,void * value)1063 static int ov5640_set_ctrl(const struct device *dev, unsigned int cid, void *value)
1064 {
1065 	switch (cid) {
1066 	case VIDEO_CID_TEST_PATTERN:
1067 		return ov5640_set_ctrl_test_pattern(dev, (int)value);
1068 	case VIDEO_CID_HUE:
1069 		return ov5640_set_ctrl_hue(dev, (int)value);
1070 	case VIDEO_CID_SATURATION:
1071 		return ov5640_set_ctrl_saturation(dev, (int)(value));
1072 	case VIDEO_CID_BRIGHTNESS:
1073 		return ov5640_set_ctrl_brightness(dev, (int)(value));
1074 	case VIDEO_CID_CONTRAST:
1075 		return ov5640_set_ctrl_contrast(dev, (int)value);
1076 	case VIDEO_CID_GAIN:
1077 		return ov5640_set_ctrl_gain(dev, (int)(value));
1078 	case VIDEO_CID_HFLIP:
1079 		return ov5640_set_ctrl_hflip(dev, (int)(value));
1080 	case VIDEO_CID_VFLIP:
1081 		return ov5640_set_ctrl_vflip(dev, (int)(value));
1082 	case VIDEO_CID_POWER_LINE_FREQUENCY:
1083 		return ov5640_set_ctrl_power_line_freq(dev, (int)(value));
1084 	default:
1085 		return -ENOTSUP;
1086 	}
1087 }
1088 
ov5640_get_ctrl(const struct device * dev,unsigned int cid,void * value)1089 static inline int ov5640_get_ctrl(const struct device *dev, unsigned int cid, void *value)
1090 {
1091 	struct ov5640_data *drv_data = dev->data;
1092 
1093 	switch (cid) {
1094 	case VIDEO_CID_PIXEL_RATE:
1095 		*((uint64_t *)value) = drv_data->cur_pixrate;
1096 
1097 		return 0;
1098 	default:
1099 		return -ENOTSUP;
1100 	}
1101 }
1102 
ov5640_get_frmival(const struct device * dev,enum video_endpoint_id ep,struct video_frmival * frmival)1103 static int ov5640_get_frmival(const struct device *dev, enum video_endpoint_id ep,
1104 			      struct video_frmival *frmival)
1105 {
1106 	struct ov5640_data *drv_data = dev->data;
1107 
1108 	if (ov5640_is_dvp(dev)) {
1109 		return -ENOTSUP;
1110 	}
1111 
1112 	frmival->numerator = 1;
1113 	frmival->denominator = drv_data->cur_frmrate;
1114 
1115 	return 0;
1116 }
1117 
ov5640_enum_frmival(const struct device * dev,enum video_endpoint_id ep,struct video_frmival_enum * fie)1118 static int ov5640_enum_frmival(const struct device *dev, enum video_endpoint_id ep,
1119 			       struct video_frmival_enum *fie)
1120 {
1121 	uint8_t i = 0;
1122 
1123 	if (ov5640_is_dvp(dev)) {
1124 		return -ENOTSUP;
1125 	}
1126 
1127 	for (i = 0; i < ARRAY_SIZE(csi2_modes); i++) {
1128 		if (fie->format->width == csi2_modes[i].width &&
1129 		    fie->format->height == csi2_modes[i].height) {
1130 			break;
1131 		}
1132 	}
1133 
1134 	if (i == ARRAY_SIZE(csi2_modes) || fie->index >= ARRAY_SIZE(ov5640_frame_rates) ||
1135 	    ov5640_frame_rates[fie->index] > csi2_modes[i].max_frmrate) {
1136 		return -EINVAL;
1137 	}
1138 
1139 	fie->type = VIDEO_FRMIVAL_TYPE_DISCRETE;
1140 	fie->discrete.numerator = 1;
1141 	fie->discrete.denominator = ov5640_frame_rates[fie->index];
1142 
1143 	return 0;
1144 }
1145 
1146 static DEVICE_API(video, ov5640_driver_api) = {
1147 	.set_format = ov5640_set_fmt,
1148 	.get_format = ov5640_get_fmt,
1149 	.get_caps = ov5640_get_caps,
1150 	.set_stream = ov5640_set_stream,
1151 	.set_ctrl = ov5640_set_ctrl,
1152 	.get_ctrl = ov5640_get_ctrl,
1153 	.set_frmival = ov5640_set_frmival,
1154 	.get_frmival = ov5640_get_frmival,
1155 	.enum_frmival = ov5640_enum_frmival,
1156 };
1157 
ov5640_init(const struct device * dev)1158 static int ov5640_init(const struct device *dev)
1159 {
1160 	const struct ov5640_config *cfg = dev->config;
1161 	struct video_format fmt;
1162 	uint16_t chip_id;
1163 	int ret;
1164 
1165 	if (!device_is_ready(cfg->i2c.bus)) {
1166 		LOG_ERR("Bus device is not ready");
1167 		return -ENODEV;
1168 	}
1169 
1170 	if (!gpio_is_ready_dt(&cfg->reset_gpio)) {
1171 		LOG_ERR("%s: device %s is not ready", dev->name, cfg->reset_gpio.port->name);
1172 		return -ENODEV;
1173 	}
1174 
1175 	if (!gpio_is_ready_dt(&cfg->powerdown_gpio)) {
1176 		LOG_ERR("%s: device %s is not ready", dev->name, cfg->powerdown_gpio.port->name);
1177 		return -ENODEV;
1178 	}
1179 
1180 	/* Power up sequence */
1181 	if (cfg->powerdown_gpio.port != NULL) {
1182 		ret = gpio_pin_configure_dt(&cfg->powerdown_gpio, GPIO_OUTPUT_ACTIVE);
1183 		if (ret) {
1184 			return ret;
1185 		}
1186 	}
1187 
1188 	if (cfg->reset_gpio.port != NULL) {
1189 		ret = gpio_pin_configure_dt(&cfg->reset_gpio, GPIO_OUTPUT_ACTIVE);
1190 		if (ret) {
1191 			return ret;
1192 		}
1193 	}
1194 
1195 	k_sleep(K_MSEC(5));
1196 
1197 	if (cfg->powerdown_gpio.port != NULL) {
1198 		gpio_pin_set_dt(&cfg->powerdown_gpio, 0);
1199 	}
1200 
1201 	k_sleep(K_MSEC(1));
1202 
1203 	if (cfg->reset_gpio.port != NULL) {
1204 		gpio_pin_set_dt(&cfg->reset_gpio, 0);
1205 	}
1206 
1207 	k_sleep(K_MSEC(20));
1208 
1209 	/* Reset all registers */
1210 	ret = ov5640_write_reg(&cfg->i2c, SCCB_SYS_CTRL1_REG, 0x11);
1211 	if (ret) {
1212 		LOG_ERR("Unable to write to reset all registers");
1213 		return -EIO;
1214 	}
1215 
1216 	/* Software reset */
1217 	ret = ov5640_write_reg(&cfg->i2c, SYS_CTRL0_REG, SYS_CTRL0_SW_RST);
1218 	if (ret) {
1219 		LOG_ERR("Unable to perform software reset");
1220 		return -EIO;
1221 	}
1222 
1223 	k_sleep(K_MSEC(5));
1224 
1225 	/* Initialize register values */
1226 	ret = ov5640_write_multi_regs(&cfg->i2c, init_params_common,
1227 				      ARRAY_SIZE(init_params_common));
1228 	if (ret) {
1229 		LOG_ERR("Unable to initialize the sensor");
1230 		return -EIO;
1231 	}
1232 
1233 	if (ov5640_is_dvp(dev)) {
1234 		ret = ov5640_write_multi_regs(&cfg->i2c, init_params_dvp,
1235 					      ARRAY_SIZE(init_params_dvp));
1236 
1237 		if (ret) {
1238 			LOG_ERR("Unable to initialize the sensor with DVP parameters");
1239 			return -EIO;
1240 		}
1241 	} else {
1242 		/* Set virtual channel */
1243 		ret = ov5640_modify_reg(&cfg->i2c, 0x4814, 3U << 6,
1244 					(uint8_t)(DEFAULT_MIPI_CHANNEL) << 6);
1245 		if (ret) {
1246 			LOG_ERR("Unable to set virtual channel");
1247 			return -EIO;
1248 		}
1249 	}
1250 
1251 	/* Check sensor chip id */
1252 	ret = ov5640_read_reg(&cfg->i2c, CHIP_ID_REG, &chip_id, sizeof(chip_id));
1253 	if (ret) {
1254 		LOG_ERR("Unable to read sensor chip ID, ret = %d", ret);
1255 		return -ENODEV;
1256 	}
1257 
1258 	if (chip_id != CHIP_ID_VAL) {
1259 		LOG_ERR("Wrong chip ID: %04x (expected %04x)", chip_id, CHIP_ID_VAL);
1260 		return -ENODEV;
1261 	}
1262 
1263 	/* Set default format */
1264 	fmt.pixelformat = VIDEO_PIX_FMT_RGB565;
1265 	if (ov5640_is_dvp(dev)) {
1266 		/* Set default resolution to QQVGA (160x120) */
1267 		fmt.width = 160;
1268 		fmt.height = 120;
1269 	} else {
1270 		/* Set default resolution to 720p */
1271 		fmt.width = 1280;
1272 		fmt.height = 720;
1273 	}
1274 	fmt.pitch = fmt.width * 2;
1275 	ret = ov5640_set_fmt(dev, VIDEO_EP_OUT, &fmt);
1276 	if (ret) {
1277 		LOG_ERR("Unable to configure default format");
1278 		return -EIO;
1279 	}
1280 
1281 	return 0;
1282 }
1283 
1284 #define OV5640_INIT(n)                                                                             \
1285 	static struct ov5640_data ov5640_data_##n;                                                 \
1286                                                                                                    \
1287 	static const struct ov5640_config ov5640_cfg_##n = {                                       \
1288 		.i2c = I2C_DT_SPEC_INST_GET(n),                                                    \
1289 		.reset_gpio = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {0}),                       \
1290 		.powerdown_gpio = GPIO_DT_SPEC_INST_GET_OR(n, powerdown_gpios, {0}),               \
1291 		.bus_type = DT_PROP_OR(DT_CHILD(DT_INST_CHILD(n, port), endpoint), bus_type,       \
1292 				       VIDEO_BUS_TYPE_CSI2_DPHY),                                  \
1293 	};                                                                                         \
1294                                                                                                    \
1295 	DEVICE_DT_INST_DEFINE(n, &ov5640_init, NULL, &ov5640_data_##n, &ov5640_cfg_##n,            \
1296 			      POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, &ov5640_driver_api);
1297 
1298 DT_INST_FOREACH_STATUS_OKAY(OV5640_INIT)
1299