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