1 /*
2 * Copyright (c) 2020, FrankLi Limited
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ovti_ov7725
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/device.h>
11 #include <zephyr/sys/byteorder.h>
12 #include <zephyr/logging/log.h>
13 #include <zephyr/drivers/video.h>
14 #include <zephyr/drivers/i2c.h>
15 #include <zephyr/drivers/gpio.h>
16
17 LOG_MODULE_REGISTER(video_ov7725, CONFIG_VIDEO_LOG_LEVEL);
18
19 #define OV7725_REVISION 0x7721U
20
21 #define OV7725_GAIN 0x00U
22 #define OV7725_BLUE 0x01U
23 #define OV7725_RED 0x02U
24 #define OV7725_GREEN 0x03U
25 #define OV7725_BAVG 0x05U
26 #define OV7725_GAVG 0x06U
27 #define OV7725_RAVG 0x07U
28 #define OV7725_AECH 0x08U
29 #define OV7725_COM2 0x09U
30 #define OV7725_PID 0x0AU
31 #define OV7725_VER 0x0BU
32 #define OV7725_COM3 0x0CU
33 #define OV7725_COM4 0x0DU
34 #define OV7725_COM5 0x0EU
35 #define OV7725_COM6 0x0FU
36 #define OV7725_AEC 0x10U
37 #define OV7725_CLKRC 0x11U
38 #define OV7725_COM7 0x12U
39 #define OV7725_COM8 0x13U
40 #define OV7725_COM9 0x14U
41 #define OV7725_COM10 0x15U
42 #define OV7725_REG16 0x16U
43 #define OV7725_HSTART 0x17U
44 #define OV7725_HSIZE 0x18U
45 #define OV7725_VSTART 0x19U
46 #define OV7725_VSIZE 0x1AU
47 #define OV7725_PSHFT 0x1BU
48 #define OV7725_MIDH 0x1CU
49 #define OV7725_MIDL 0x1DU
50 #define OV7725_LAEC 0x1FU
51 #define OV7725_COM11 0x20U
52 #define OV7725_BDBASE 0x22U
53 #define OV7725_BDMSTEP 0x23U
54 #define OV7725_AEW 0x24U
55 #define OV7725_AEB 0x25U
56 #define OV7725_VPT 0x26U
57 #define OV7725_REG28 0x28U
58 #define OV7725_HOUTSIZE 0x29U
59 #define OV7725_EXHCH 0x2AU
60 #define OV7725_EXHCL 0x2BU
61 #define OV7725_VOUTSIZE 0x2CU
62 #define OV7725_ADVFL 0x2DU
63 #define OV7725_ADVFH 0x2EU
64 #define OV7725_YAVE 0x2FU
65 #define OV7725_LUMHTH 0x30U
66 #define OV7725_LUMLTH 0x31U
67 #define OV7725_HREF 0x32U
68 #define OV7725_DM_LNL 0x33U
69 #define OV7725_DM_LNH 0x34U
70 #define OV7725_ADOFF_B 0x35U
71 #define OV7725_ADOFF_R 0x36U
72 #define OV7725_ADOFF_GB 0x37U
73 #define OV7725_ADOFF_GR 0x38U
74 #define OV7725_OFF_B 0x39U
75 #define OV7725_OFF_R 0x3AU
76 #define OV7725_OFF_GB 0x3BU
77 #define OV7725_OFF_GR 0x3CU
78 #define OV7725_COM12 0x3DU
79 #define OV7725_COM13 0x3EU
80 #define OV7725_COM14 0x3FU
81 #define OV7725_COM16 0x41U
82 #define OV7725_TGT_B 0x42U
83 #define OV7725_TGT_R 0x43U
84 #define OV7725_TGT_GB 0x44U
85 #define OV7725_TGT_GR 0x45U
86 #define OV7725_LC_CTR 0x46U
87 #define OV7725_LC_XC 0x47U
88 #define OV7725_LC_YC 0x48U
89 #define OV7725_LC_COEF 0x49U
90 #define OV7725_LC_RADI 0x4AU
91 #define OV7725_LC_COEFB 0x4BU
92 #define OV7725_LC_COEFR 0x4CU
93 #define OV7725_FIXGAIN 0x4DU
94 #define OV7725_AREF1 0x4FU
95 #define OV7725_AREF6 0x54U
96 #define OV7725_UFIX 0x60U
97 #define OV7725_VFIX 0x61U
98 #define OV7725_AWBB_BLK 0x62U
99 #define OV7725_AWB_CTRL0 0x63U
100 #define OV7725_DSP_CTRL1 0x64U
101 #define OV7725_DSP_CTRL2 0x65U
102 #define OV7725_DSP_CTRL3 0x66U
103 #define OV7725_DSP_CTRL4 0x67U
104 #define OV7725_AWB_BIAS 0x68U
105 #define OV7725_AWB_CTRL1 0x69U
106 #define OV7725_AWB_CTRL2 0x6AU
107 #define OV7725_AWB_CTRL3 0x6BU
108 #define OV7725_AWB_CTRL4 0x6CU
109 #define OV7725_AWB_CTRL5 0x6DU
110 #define OV7725_AWB_CTRL6 0x6EU
111 #define OV7725_AWB_CTRL7 0x6FU
112 #define OV7725_AWB_CTRL8 0x70U
113 #define OV7725_AWB_CTRL9 0x71U
114 #define OV7725_AWB_CTRL10 0x72U
115 #define OV7725_AWB_CTRL11 0x73U
116 #define OV7725_AWB_CTRL12 0x74U
117 #define OV7725_AWB_CTRL13 0x75U
118 #define OV7725_AWB_CTRL14 0x76U
119 #define OV7725_AWB_CTRL15 0x77U
120 #define OV7725_AWB_CTRL16 0x78U
121 #define OV7725_AWB_CTRL17 0x79U
122 #define OV7725_AWB_CTRL18 0x7AU
123 #define OV7725_AWB_CTRL19 0x7BU
124 #define OV7725_AWB_CTRL20 0x7CU
125 #define OV7725_AWB_CTRL21 0x7DU
126 #define OV7725_GAM1 0x7EU
127 #define OV7725_GAM2 0x7FU
128 #define OV7725_GAM3 0x80U
129 #define OV7725_GAM4 0x81U
130 #define OV7725_GAM5 0x82U
131 #define OV7725_GAM6 0x83U
132 #define OV7725_GAM7 0x84U
133 #define OV7725_GAM8 0x85U
134 #define OV7725_GAM9 0x86U
135 #define OV7725_GAM10 0x87U
136 #define OV7725_GAM11 0x88U
137 #define OV7725_GAM12 0x89U
138 #define OV7725_GAM13 0x8AU
139 #define OV7725_GAM14 0x8BU
140 #define OV7725_GAM15 0x8CU
141 #define OV7725_SLOP 0x8DU
142 #define OV7725_DNSTH 0x8EU
143 #define OV7725_EDGE0 0x8FU
144 #define OV7725_EDGE1 0x90U
145 #define OV7725_DNSOFF 0x91U
146 #define OV7725_EDGE2 0x92U
147 #define OV7725_EDGE3 0x93U
148 #define OV7725_MTX1 0x94U
149 #define OV7725_MTX2 0x95U
150 #define OV7725_MTX3 0x96U
151 #define OV7725_MTX4 0x97U
152 #define OV7725_MTX5 0x98U
153 #define OV7725_MTX6 0x99U
154 #define OV7725_MTX_CTRL 0x9AU
155 #define OV7725_BRIGHT 0x9BU
156 #define OV7725_CNST 0x9CU
157 #define OV7725_UVADJ0 0x9EU
158 #define OV7725_UVADJ1 0x9FU
159 #define OV7725_SCAL0 0xA0U
160 #define OV7725_SCAL1 0xA1U
161 #define OV7725_SCAL2 0xA2U
162 #define OV7725_SDE 0xA6U
163 #define OV7725_USAT 0xA7U
164 #define OV7725_VSAT 0xA8U
165 #define OV7725_HUECOS 0xA9U
166 #define OV7725_HUESIN 0xAAU
167 #define OV7725_SIGN 0xABU
168 #define OV7725_DSPAUTO 0xACU
169
170 #define OV7725_COM10_VSYNC_NEG_MASK BIT(1)
171 #define OV7725_COM10_HREF_REVERSE_MASK BIT(3)
172 #define OV7725_COM10_PCLK_REVERSE_MASK BIT(4)
173 #define OV7725_COM10_PCLK_OUT_MASK BIT(5)
174 #define OV7725_COM10_DATA_NEG_MASK BIT(7)
175
176 struct ov7725_config {
177 struct i2c_dt_spec i2c;
178 #if DT_INST_NODE_HAS_PROP(0, reset_gpios)
179 struct gpio_dt_spec reset_gpio;
180 #endif
181 };
182
183 struct ov7725_data {
184 struct video_format fmt;
185 };
186
187 struct ov7725_clock {
188 uint32_t input_clk;
189 uint32_t framerate;
190 uint8_t clkrc; /*!< Register CLKRC. */
191 uint8_t com4; /*!< Register COM4. */
192 uint8_t dm_lnl; /*!< Register DM_LNL. */
193 };
194
195 struct ov7725_pixel_format {
196 uint32_t pixel_format;
197 uint8_t com7;
198 };
199
200 struct ov7725_reg {
201 uint8_t addr;
202 uint8_t value;
203 };
204
205 static const struct ov7725_clock ov7725_clock_configs[] = {
206 { .input_clk = 24000000, .framerate = 30,
207 .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x00 },
208 { .input_clk = 24000000, .framerate = 15,
209 .clkrc = 0x03, .com4 = 0x41, .dm_lnl = 0x00 },
210 { .input_clk = 24000000, .framerate = 25,
211 .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x66 },
212 { .input_clk = 24000000, .framerate = 14,
213 .clkrc = 0x03, .com4 = 0x41, .dm_lnl = 0x1a },
214 { .input_clk = 26000000, .framerate = 30,
215 .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x2b },
216 { .input_clk = 26000000, .framerate = 15,
217 .clkrc = 0x03, .com4 = 0x41, .dm_lnl = 0x2b },
218 { .input_clk = 26000000, .framerate = 25,
219 .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x99 },
220 { .input_clk = 26000000, .framerate = 14,
221 .clkrc = 0x03, .com4 = 0x41, .dm_lnl = 0x46 },
222 { .input_clk = 13000000, .framerate = 30,
223 .clkrc = 0x00, .com4 = 0x41, .dm_lnl = 0x2b },
224 { .input_clk = 13000000, .framerate = 15,
225 .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x2b },
226 { .input_clk = 13000000, .framerate = 25,
227 .clkrc = 0x00, .com4 = 0x41, .dm_lnl = 0x99 },
228 { .input_clk = 13000000, .framerate = 14,
229 .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x46 },
230 };
231
232
233 static const struct ov7725_pixel_format ov7725_pf_configs[] = {
234 { .pixel_format = VIDEO_PIX_FMT_RGB565, .com7 = (1 << 2) | (2) }
235 };
236
237 static const struct ov7725_reg ov7725_init_reg_tb[] = {
238 /*Output config*/
239 { OV7725_CLKRC, 0x00 },
240 { OV7725_COM7, 0x06 },
241 { OV7725_HSTART, 0x3f },
242 { OV7725_HSIZE, 0x50 },
243 { OV7725_VSTART, 0x03 },
244 { OV7725_VSIZE, 0x78 },
245 { OV7725_HREF, 0x00 },
246 { OV7725_HOUTSIZE, 0x50 },
247 { OV7725_VOUTSIZE, 0x78 },
248
249 /*DSP control*/
250 { OV7725_TGT_B, 0x7f },
251 { OV7725_FIXGAIN, 0x09 },
252 { OV7725_AWB_CTRL0, 0xe0 },
253 { OV7725_DSP_CTRL1, 0xff },
254 { OV7725_DSP_CTRL2, 0x00 },
255 { OV7725_DSP_CTRL3, 0x00 },
256 { OV7725_DSP_CTRL4, 0x00 },
257
258 /*AGC AEC AWB*/
259 { OV7725_COM8, 0xf0 },
260 { OV7725_COM4, 0x81 },
261 { OV7725_COM6, 0xc5 },
262 { OV7725_COM9, 0x11 },
263 { OV7725_BDBASE, 0x7F },
264 { OV7725_BDMSTEP, 0x03 },
265 { OV7725_AEW, 0x40 },
266 { OV7725_AEB, 0x30 },
267 { OV7725_VPT, 0xa1 },
268 { OV7725_EXHCL, 0x9e },
269 { OV7725_AWB_CTRL3, 0xaa },
270 { OV7725_COM8, 0xff },
271
272 /*matrix sharpness brightness contrast*/
273 { OV7725_EDGE1, 0x08 },
274 { OV7725_DNSOFF, 0x01 },
275 { OV7725_EDGE2, 0x03 },
276 { OV7725_EDGE3, 0x00 },
277 { OV7725_MTX1, 0xb0 },
278 { OV7725_MTX2, 0x9d },
279 { OV7725_MTX3, 0x13 },
280 { OV7725_MTX4, 0x16 },
281 { OV7725_MTX5, 0x7b },
282 { OV7725_MTX6, 0x91 },
283 { OV7725_MTX_CTRL, 0x1e },
284 { OV7725_BRIGHT, 0x08 },
285 { OV7725_CNST, 0x20 },
286 { OV7725_UVADJ0, 0x81 },
287 { OV7725_SDE, 0X06 },
288 { OV7725_USAT, 0x65 },
289 { OV7725_VSAT, 0x65 },
290 { OV7725_HUECOS, 0X80 },
291 { OV7725_HUESIN, 0X80 },
292
293 /*GAMMA config*/
294 { OV7725_GAM1, 0x0c },
295 { OV7725_GAM2, 0x16 },
296 { OV7725_GAM3, 0x2a },
297 { OV7725_GAM4, 0x4e },
298 { OV7725_GAM5, 0x61 },
299 { OV7725_GAM6, 0x6f },
300 { OV7725_GAM7, 0x7b },
301 { OV7725_GAM8, 0x86 },
302 { OV7725_GAM9, 0x8e },
303 { OV7725_GAM10, 0x97 },
304 { OV7725_GAM11, 0xa4 },
305 { OV7725_GAM12, 0xaf },
306 { OV7725_GAM13, 0xc5 },
307 { OV7725_GAM14, 0xd7 },
308 { OV7725_GAM15, 0xe8 },
309 { OV7725_SLOP, 0x20 },
310
311 { OV7725_COM3, 0x40 },
312 { OV7725_COM5, 0xf5 },
313 { OV7725_COM10, 0x02 },
314 { OV7725_COM2, 0x01 }
315 };
316
ov7725_write_reg(const struct i2c_dt_spec * spec,uint8_t reg_addr,uint8_t value)317 static int ov7725_write_reg(const struct i2c_dt_spec *spec, uint8_t reg_addr,
318 uint8_t value)
319 {
320 struct i2c_msg msgs[2];
321
322 msgs[0].buf = (uint8_t *)®_addr;
323 msgs[0].len = 1;
324 msgs[0].flags = I2C_MSG_WRITE;
325
326 msgs[1].buf = (uint8_t *)&value;
327 msgs[1].len = 1;
328 msgs[1].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
329
330 return i2c_transfer_dt(spec, msgs, 2);
331 }
332
ov7725_read_reg(const struct i2c_dt_spec * spec,uint8_t reg_addr,uint8_t * value)333 static int ov7725_read_reg(const struct i2c_dt_spec *spec, uint8_t reg_addr,
334 uint8_t *value)
335 {
336 struct i2c_msg msgs[2];
337
338 msgs[0].buf = (uint8_t *)®_addr;
339 msgs[0].len = 1;
340 /*
341 * When using I2C to read the registers of the SCCB device,
342 * a stop bit is required after writing the register address
343 */
344 msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
345
346 msgs[1].buf = (uint8_t *)value;
347 msgs[1].len = 1;
348 msgs[1].flags = I2C_MSG_READ | I2C_MSG_STOP | I2C_MSG_RESTART;
349
350 return i2c_transfer_dt(spec, msgs, 2);
351 }
352
ov7725_modify_reg(const struct i2c_dt_spec * spec,uint8_t reg_addr,uint8_t clear_mask,uint8_t value)353 int ov7725_modify_reg(const struct i2c_dt_spec *spec,
354 uint8_t reg_addr,
355 uint8_t clear_mask,
356 uint8_t value)
357 {
358 int ret;
359 uint8_t set_value;
360
361 ret = ov7725_read_reg(spec, reg_addr, &set_value);
362
363 if (ret == 0) {
364 set_value = (set_value & (~clear_mask)) |
365 (set_value & clear_mask);
366 ret = ov7725_write_reg(spec, reg_addr, set_value);
367 }
368
369
370 return ret;
371 }
372
ov7725_write_all(const struct device * dev,const struct ov7725_reg * regs,uint16_t reg_num)373 static int ov7725_write_all(const struct device *dev,
374 const struct ov7725_reg *regs,
375 uint16_t reg_num)
376 {
377 uint16_t i = 0;
378 const struct ov7725_config *cfg = dev->config;
379
380 for (i = 0; i < reg_num; i++) {
381 int err;
382
383 err = ov7725_write_reg(&cfg->i2c, regs[i].addr, regs[i].value);
384 if (err) {
385 return err;
386 }
387 }
388
389 return 0;
390 }
391
ov7725_set_clock(const struct device * dev,unsigned int framerate,unsigned int input_clk)392 static int ov7725_set_clock(const struct device *dev,
393 unsigned int framerate,
394 unsigned int input_clk)
395 {
396 const struct ov7725_config *cfg = dev->config;
397
398 for (unsigned int i = 0; i < ARRAY_SIZE(ov7725_clock_configs); i++) {
399 if ((ov7725_clock_configs[i].framerate == framerate) &&
400 (ov7725_clock_configs[i].input_clk == input_clk)) {
401 ov7725_write_reg(&cfg->i2c, OV7725_CLKRC,
402 ov7725_clock_configs[i].clkrc);
403 ov7725_modify_reg(&cfg->i2c, OV7725_COM4, 0xc0,
404 ov7725_clock_configs[i].com4);
405 ov7725_write_reg(&cfg->i2c, OV7725_EXHCL, 0x00);
406 ov7725_write_reg(&cfg->i2c, OV7725_DM_LNL,
407 ov7725_clock_configs[i].dm_lnl);
408 ov7725_write_reg(&cfg->i2c, OV7725_DM_LNH, 0x00);
409 ov7725_write_reg(&cfg->i2c, OV7725_ADVFL, 0x00);
410 ov7725_write_reg(&cfg->i2c, OV7725_ADVFH, 0x00);
411 return ov7725_write_reg(&cfg->i2c, OV7725_COM5, 0x65);
412 }
413 }
414
415 return -1;
416 }
417
ov7725_set_fmt(const struct device * dev,enum video_endpoint_id ep,struct video_format * fmt)418 static int ov7725_set_fmt(const struct device *dev,
419 enum video_endpoint_id ep,
420 struct video_format *fmt)
421 {
422 struct ov7725_data *drv_data = dev->data;
423 const struct ov7725_config *cfg = dev->config;
424 uint8_t com10 = 0;
425 uint16_t width, height;
426 uint16_t hstart, vstart, hsize;
427 int ret;
428
429 /* we only support one format for now (VGA RGB565) */
430 if (fmt->pixelformat != VIDEO_PIX_FMT_RGB565 || fmt->height != 480 ||
431 fmt->width != 640) {
432 return -ENOTSUP;
433 }
434
435 width = fmt->width;
436 height = fmt->height;
437
438 if (!memcmp(&drv_data->fmt, fmt, sizeof(drv_data->fmt))) {
439 /* nothing to do */
440 return 0;
441 }
442
443 drv_data->fmt = *fmt;
444
445 /* Configure Sensor */
446 ret = ov7725_write_all(dev, ov7725_init_reg_tb,
447 ARRAY_SIZE(ov7725_init_reg_tb));
448 if (ret) {
449 LOG_ERR("Unable to write ov7725 config");
450 return ret;
451 }
452
453 /* Set clock : framerate 30fps, input clock 24M*/
454 ov7725_set_clock(dev, 30, 24000000);
455
456 /* Set output format */
457 for (uint8_t i = 0; i < ARRAY_SIZE(ov7725_pf_configs); i++) {
458 if (ov7725_pf_configs[i].pixel_format == fmt->pixelformat) {
459 ret = ov7725_modify_reg(&cfg->i2c,
460 OV7725_COM7,
461 0x1FU,
462 ov7725_pf_configs[i].com7);
463 if (ret) {
464 LOG_ERR("Unable to write ov7725 pixel format");
465 return ret;
466 }
467 }
468 }
469
470 ov7725_modify_reg(&cfg->i2c, OV7725_COM7, (1 << 5), (0 << 5));
471
472 com10 |= OV7725_COM10_VSYNC_NEG_MASK;
473 ov7725_write_reg(&cfg->i2c, OV7725_COM10, com10);
474
475 /* Don't swap output MSB/LSB. */
476 ov7725_write_reg(&cfg->i2c, OV7725_COM3, 0x00);
477
478 /*
479 * Output drive capability
480 * 0: 1X
481 * 1: 2X
482 * 2: 3X
483 * 3: 4X
484 */
485 ov7725_modify_reg(&cfg->i2c, OV7725_COM2, 0x03, 0x03);
486
487 /* Resolution and timing. */
488 hstart = 0x22U << 2U;
489 vstart = 0x07U << 1U;
490 hsize = width + 16U;
491
492 /* Set the window size. */
493 ov7725_write_reg(&cfg->i2c, OV7725_HSTART, hstart >> 2U);
494 ov7725_write_reg(&cfg->i2c, OV7725_HSIZE, hsize >> 2U);
495 ov7725_write_reg(&cfg->i2c, OV7725_VSTART, vstart >> 1U);
496 ov7725_write_reg(&cfg->i2c, OV7725_VSIZE, height >> 1U);
497 ov7725_write_reg(&cfg->i2c, OV7725_HOUTSIZE, width >> 2U);
498 ov7725_write_reg(&cfg->i2c, OV7725_VOUTSIZE, height >> 1U);
499 ov7725_write_reg(&cfg->i2c, OV7725_HREF,
500 ((vstart & 1U) << 6U) |
501 ((hstart & 3U) << 4U) |
502 ((height & 1U) << 2U) |
503 ((hsize & 3U) << 0U));
504 return ov7725_write_reg(&cfg->i2c, OV7725_EXHCH,
505 ((height & 1U) << 2U) |
506 ((width & 3U) << 0U));
507 }
508
ov7725_get_fmt(const struct device * dev,enum video_endpoint_id ep,struct video_format * fmt)509 static int ov7725_get_fmt(const struct device *dev,
510 enum video_endpoint_id ep,
511 struct video_format *fmt)
512 {
513 struct ov7725_data *drv_data = dev->data;
514
515 *fmt = drv_data->fmt;
516
517 return 0;
518 }
519
ov7725_stream_start(const struct device * dev)520 static int ov7725_stream_start(const struct device *dev)
521 {
522 return 0;
523 }
524
ov7725_stream_stop(const struct device * dev)525 static int ov7725_stream_stop(const struct device *dev)
526 {
527 return 0;
528 }
529
530 static const struct video_format_cap fmts[] = {
531 {
532 .pixelformat = VIDEO_PIX_FMT_RGB565,
533 .width_min = 640,
534 .width_max = 640,
535 .height_min = 480,
536 .height_max = 480,
537 .width_step = 0,
538 .height_step = 0,
539 },
540 { 0 }
541 };
542
ov7725_get_caps(const struct device * dev,enum video_endpoint_id ep,struct video_caps * caps)543 static int ov7725_get_caps(const struct device *dev,
544 enum video_endpoint_id ep,
545 struct video_caps *caps)
546 {
547 caps->format_caps = fmts;
548 return 0;
549 }
550
551 static DEVICE_API(video, ov7725_driver_api) = {
552 .set_format = ov7725_set_fmt,
553 .get_format = ov7725_get_fmt,
554 .get_caps = ov7725_get_caps,
555 .stream_start = ov7725_stream_start,
556 .stream_stop = ov7725_stream_stop,
557 };
558
ov7725_init(const struct device * dev)559 static int ov7725_init(const struct device *dev)
560 {
561 const struct ov7725_config *cfg = dev->config;
562 struct video_format fmt;
563 uint8_t pid, ver;
564 int ret;
565
566 #if DT_INST_NODE_HAS_PROP(0, reset_gpios)
567 ret = gpio_pin_configure_dt(&cfg->reset_gpio, GPIO_OUTPUT_ACTIVE);
568 if (ret) {
569 return ret;
570 }
571
572 gpio_pin_set_dt(&cfg->reset_gpio, 0);
573 k_sleep(K_MSEC(1));
574 gpio_pin_set_dt(&cfg->reset_gpio, 1);
575 k_sleep(K_MSEC(1));
576 #endif
577
578 /* Identify the device. */
579 ret = ov7725_read_reg(&cfg->i2c, OV7725_PID, &pid);
580 if (ret) {
581 LOG_ERR("Unable to read PID");
582 return -ENODEV;
583 }
584
585 ret = ov7725_read_reg(&cfg->i2c, OV7725_VER, &ver);
586 if (ret) {
587 LOG_ERR("Unable to read VER");
588 return -ENODEV;
589 }
590
591 if (OV7725_REVISION != (((uint32_t)pid << 8U) | (uint32_t)ver)) {
592 LOG_ERR("OV7725 Get Vision fail\n");
593 return -ENODEV;
594 }
595
596 /* Device identify OK, perform software reset. */
597 ov7725_write_reg(&cfg->i2c, OV7725_COM7, 0x80);
598
599 k_sleep(K_MSEC(2));
600
601 /* set default/init format VGA RGB565 */
602 fmt.pixelformat = VIDEO_PIX_FMT_RGB565;
603 fmt.width = 640;
604 fmt.height = 480;
605 fmt.pitch = 640 * 2;
606 ret = ov7725_set_fmt(dev, VIDEO_EP_OUT, &fmt);
607 if (ret) {
608 LOG_ERR("Unable to configure default format");
609 return -EIO;
610 }
611
612 return 0;
613 }
614
615 /* Unique Instance */
616 static const struct ov7725_config ov7725_cfg_0 = {
617 .i2c = I2C_DT_SPEC_INST_GET(0),
618 #if DT_INST_NODE_HAS_PROP(0, reset_gpios)
619 .reset_gpio = GPIO_DT_SPEC_INST_GET(0, reset_gpios),
620 #endif
621 };
622 static struct ov7725_data ov7725_data_0;
623
ov7725_init_0(const struct device * dev)624 static int ov7725_init_0(const struct device *dev)
625 {
626 const struct ov7725_config *cfg = dev->config;
627
628 if (!device_is_ready(cfg->i2c.bus)) {
629 LOG_ERR("Bus device is not ready");
630 return -ENODEV;
631 }
632
633 #if DT_INST_NODE_HAS_PROP(0, reset_gpios)
634 if (!gpio_is_ready_dt(&cfg->reset_gpio)) {
635 LOG_ERR("%s: device %s is not ready", dev->name,
636 cfg->reset_gpio.port->name);
637 return -ENODEV;
638 }
639 #endif
640
641 return ov7725_init(dev);
642 }
643
644 DEVICE_DT_INST_DEFINE(0, &ov7725_init_0, NULL,
645 &ov7725_data_0, &ov7725_cfg_0,
646 POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY,
647 &ov7725_driver_api);
648