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 #include <zephyr.h>
9 #include <device.h>
10 
11 #include <sys/byteorder.h>
12 
13 #include <drivers/video.h>
14 #include <drivers/i2c.h>
15 #include <drivers/gpio.h>
16 
17 #define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
18 #include <logging/log.h>
19 LOG_MODULE_REGISTER(ov7725);
20 
21 #define OV7725_REVISION  0x7721U
22 
23 #define OV7725_GAIN       0x00U
24 #define OV7725_BLUE       0x01U
25 #define OV7725_RED        0x02U
26 #define OV7725_GREEN      0x03U
27 #define OV7725_BAVG       0x05U
28 #define OV7725_GAVG       0x06U
29 #define OV7725_RAVG       0x07U
30 #define OV7725_AECH       0x08U
31 #define OV7725_COM2       0x09U
32 #define OV7725_PID        0x0AU
33 #define OV7725_VER        0x0BU
34 #define OV7725_COM3       0x0CU
35 #define OV7725_COM4       0x0DU
36 #define OV7725_COM5       0x0EU
37 #define OV7725_COM6       0x0FU
38 #define OV7725_AEC        0x10U
39 #define OV7725_CLKRC      0x11U
40 #define OV7725_COM7       0x12U
41 #define OV7725_COM8       0x13U
42 #define OV7725_COM9       0x14U
43 #define OV7725_COM10      0x15U
44 #define OV7725_REG16      0x16U
45 #define OV7725_HSTART     0x17U
46 #define OV7725_HSIZE      0x18U
47 #define OV7725_VSTART     0x19U
48 #define OV7725_VSIZE      0x1AU
49 #define OV7725_PSHFT      0x1BU
50 #define OV7725_MIDH       0x1CU
51 #define OV7725_MIDL       0x1DU
52 #define OV7725_LAEC       0x1FU
53 #define OV7725_COM11      0x20U
54 #define OV7725_BDBASE     0x22U
55 #define OV7725_BDMSTEP    0x23U
56 #define OV7725_AEW        0x24U
57 #define OV7725_AEB        0x25U
58 #define OV7725_VPT        0x26U
59 #define OV7725_REG28      0x28U
60 #define OV7725_HOUTSIZE   0x29U
61 #define OV7725_EXHCH      0x2AU
62 #define OV7725_EXHCL      0x2BU
63 #define OV7725_VOUTSIZE   0x2CU
64 #define OV7725_ADVFL      0x2DU
65 #define OV7725_ADVFH      0x2EU
66 #define OV7725_YAVE       0x2FU
67 #define OV7725_LUMHTH     0x30U
68 #define OV7725_LUMLTH     0x31U
69 #define OV7725_HREF       0x32U
70 #define OV7725_DM_LNL     0x33U
71 #define OV7725_DM_LNH     0x34U
72 #define OV7725_ADOFF_B    0x35U
73 #define OV7725_ADOFF_R    0x36U
74 #define OV7725_ADOFF_GB   0x37U
75 #define OV7725_ADOFF_GR   0x38U
76 #define OV7725_OFF_B      0x39U
77 #define OV7725_OFF_R      0x3AU
78 #define OV7725_OFF_GB     0x3BU
79 #define OV7725_OFF_GR     0x3CU
80 #define OV7725_COM12      0x3DU
81 #define OV7725_COM13      0x3EU
82 #define OV7725_COM14      0x3FU
83 #define OV7725_COM16      0x41U
84 #define OV7725_TGT_B      0x42U
85 #define OV7725_TGT_R      0x43U
86 #define OV7725_TGT_GB     0x44U
87 #define OV7725_TGT_GR     0x45U
88 #define OV7725_LC_CTR     0x46U
89 #define OV7725_LC_XC      0x47U
90 #define OV7725_LC_YC      0x48U
91 #define OV7725_LC_COEF    0x49U
92 #define OV7725_LC_RADI    0x4AU
93 #define OV7725_LC_COEFB   0x4BU
94 #define OV7725_LC_COEFR   0x4CU
95 #define OV7725_FIXGAIN    0x4DU
96 #define OV7725_AREF1      0x4FU
97 #define OV7725_AREF6      0x54U
98 #define OV7725_UFIX       0x60U
99 #define OV7725_VFIX       0x61U
100 #define OV7725_AWBB_BLK   0x62U
101 #define OV7725_AWB_CTRL0  0x63U
102 #define OV7725_DSP_CTRL1  0x64U
103 #define OV7725_DSP_CTRL2  0x65U
104 #define OV7725_DSP_CTRL3  0x66U
105 #define OV7725_DSP_CTRL4  0x67U
106 #define OV7725_AWB_BIAS   0x68U
107 #define OV7725_AWB_CTRL1  0x69U
108 #define OV7725_AWB_CTRL2  0x6AU
109 #define OV7725_AWB_CTRL3  0x6BU
110 #define OV7725_AWB_CTRL4  0x6CU
111 #define OV7725_AWB_CTRL5  0x6DU
112 #define OV7725_AWB_CTRL6  0x6EU
113 #define OV7725_AWB_CTRL7  0x6FU
114 #define OV7725_AWB_CTRL8  0x70U
115 #define OV7725_AWB_CTRL9  0x71U
116 #define OV7725_AWB_CTRL10 0x72U
117 #define OV7725_AWB_CTRL11 0x73U
118 #define OV7725_AWB_CTRL12 0x74U
119 #define OV7725_AWB_CTRL13 0x75U
120 #define OV7725_AWB_CTRL14 0x76U
121 #define OV7725_AWB_CTRL15 0x77U
122 #define OV7725_AWB_CTRL16 0x78U
123 #define OV7725_AWB_CTRL17 0x79U
124 #define OV7725_AWB_CTRL18 0x7AU
125 #define OV7725_AWB_CTRL19 0x7BU
126 #define OV7725_AWB_CTRL20 0x7CU
127 #define OV7725_AWB_CTRL21 0x7DU
128 #define OV7725_GAM1       0x7EU
129 #define OV7725_GAM2       0x7FU
130 #define OV7725_GAM3       0x80U
131 #define OV7725_GAM4       0x81U
132 #define OV7725_GAM5       0x82U
133 #define OV7725_GAM6       0x83U
134 #define OV7725_GAM7       0x84U
135 #define OV7725_GAM8       0x85U
136 #define OV7725_GAM9       0x86U
137 #define OV7725_GAM10      0x87U
138 #define OV7725_GAM11      0x88U
139 #define OV7725_GAM12      0x89U
140 #define OV7725_GAM13      0x8AU
141 #define OV7725_GAM14      0x8BU
142 #define OV7725_GAM15      0x8CU
143 #define OV7725_SLOP       0x8DU
144 #define OV7725_DNSTH      0x8EU
145 #define OV7725_EDGE0      0x8FU
146 #define OV7725_EDGE1      0x90U
147 #define OV7725_DNSOFF     0x91U
148 #define OV7725_EDGE2      0x92U
149 #define OV7725_EDGE3      0x93U
150 #define OV7725_MTX1       0x94U
151 #define OV7725_MTX2       0x95U
152 #define OV7725_MTX3       0x96U
153 #define OV7725_MTX4       0x97U
154 #define OV7725_MTX5       0x98U
155 #define OV7725_MTX6       0x99U
156 #define OV7725_MTX_CTRL   0x9AU
157 #define OV7725_BRIGHT     0x9BU
158 #define OV7725_CNST       0x9CU
159 #define OV7725_UVADJ0     0x9EU
160 #define OV7725_UVADJ1     0x9FU
161 #define OV7725_SCAL0      0xA0U
162 #define OV7725_SCAL1      0xA1U
163 #define OV7725_SCAL2      0xA2U
164 #define OV7725_SDE        0xA6U
165 #define OV7725_USAT       0xA7U
166 #define OV7725_VSAT       0xA8U
167 #define OV7725_HUECOS     0xA9U
168 #define OV7725_HUESIN     0xAAU
169 #define OV7725_SIGN       0xABU
170 #define OV7725_DSPAUTO    0xACU
171 
172 #define OV7725_COM10_VSYNC_NEG_MASK    BIT(1)
173 #define OV7725_COM10_HREF_REVERSE_MASK BIT(3)
174 #define OV7725_COM10_PCLK_REVERSE_MASK BIT(4)
175 #define OV7725_COM10_PCLK_OUT_MASK     BIT(5)
176 #define OV7725_COM10_DATA_NEG_MASK     BIT(7)
177 
178 struct ov7725_data {
179 	const struct device *i2c;
180 	const struct device *reset_gpio;
181 	uint8_t reset_pin;
182 	gpio_dt_flags_t reset_flags;
183 	struct video_format fmt;
184 	uint8_t i2c_addr;
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 shapness 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 device * dev,uint8_t reg_addr,uint8_t value)317 static int ov7725_write_reg(const struct device *dev, uint8_t reg_addr,
318 			    uint8_t value)
319 {
320 	struct ov7725_data *drv_data = dev->data;
321 	struct i2c_msg msgs[2];
322 
323 	msgs[0].buf = (uint8_t *)&reg_addr;
324 	msgs[0].len = 1;
325 	msgs[0].flags = I2C_MSG_WRITE;
326 
327 	msgs[1].buf = (uint8_t *)&value;
328 	msgs[1].len = 1;
329 	msgs[1].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
330 
331 	return i2c_transfer(drv_data->i2c, msgs, 2, drv_data->i2c_addr);
332 }
333 
ov7725_read_reg(const struct device * dev,uint8_t reg_addr,uint8_t * value)334 static int ov7725_read_reg(const struct device *dev, uint8_t reg_addr,
335 			   uint8_t *value)
336 {
337 	struct ov7725_data *drv_data = dev->data;
338 	struct i2c_msg msgs[2];
339 
340 	msgs[0].buf = (uint8_t *)&reg_addr;
341 	msgs[0].len = 1;
342 	/*
343 	 * When using I2C to read the registers of the SCCB device,
344 	 * a stop bit is required after writing the register address
345 	 */
346 	msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
347 
348 	msgs[1].buf = (uint8_t *)value;
349 	msgs[1].len = 1;
350 	msgs[1].flags = I2C_MSG_READ | I2C_MSG_STOP | I2C_MSG_RESTART;
351 
352 	return i2c_transfer(drv_data->i2c, msgs, 2, drv_data->i2c_addr);
353 }
354 
ov7725_modify_reg(const struct device * dev,uint8_t reg_addr,uint8_t clear_mask,uint8_t value)355 int ov7725_modify_reg(const struct device *dev,
356 		      uint8_t reg_addr,
357 		      uint8_t clear_mask,
358 		      uint8_t value)
359 {
360 	int ret;
361 	uint8_t set_value;
362 
363 	ret = ov7725_read_reg(dev, reg_addr, &set_value);
364 
365 	if (ret == 0) {
366 		set_value = (set_value & (~clear_mask)) |
367 				(set_value & clear_mask);
368 		ret = ov7725_write_reg(dev, reg_addr, set_value);
369 	}
370 
371 
372 	return ret;
373 }
374 
ov7725_write_all(const struct device * dev,const struct ov7725_reg * regs,uint16_t reg_num)375 static int ov7725_write_all(const struct device *dev,
376 			    const struct ov7725_reg *regs,
377 			    uint16_t reg_num)
378 {
379 	uint16_t i = 0;
380 
381 	for (i = 0; i < reg_num; i++) {
382 		int err;
383 
384 		err = ov7725_write_reg(dev, regs[i].addr, regs[i].value);
385 		if (err) {
386 			return err;
387 		}
388 	}
389 
390 	return 0;
391 }
392 
ov7725_set_clock(const struct device * dev,unsigned int framerate,unsigned int input_clk)393 static int ov7725_set_clock(const struct device *dev,
394 				unsigned int framerate,
395 				unsigned int input_clk)
396 {
397 	for (unsigned int i = 0; i < ARRAY_SIZE(ov7725_clock_configs); i++) {
398 		if ((ov7725_clock_configs[i].framerate == framerate) &&
399 			(ov7725_clock_configs[i].input_clk == input_clk)) {
400 			ov7725_write_reg(dev, OV7725_CLKRC,
401 						ov7725_clock_configs[i].clkrc);
402 			ov7725_modify_reg(dev, OV7725_COM4, 0xc0,
403 						ov7725_clock_configs[i].com4);
404 			ov7725_write_reg(dev, OV7725_EXHCL, 0x00);
405 			ov7725_write_reg(dev, OV7725_DM_LNL,
406 						ov7725_clock_configs[i].dm_lnl);
407 			ov7725_write_reg(dev, OV7725_DM_LNH, 0x00);
408 			ov7725_write_reg(dev, OV7725_ADVFL, 0x00);
409 			ov7725_write_reg(dev, OV7725_ADVFH, 0x00);
410 			return ov7725_write_reg(dev, OV7725_COM5, 0x65);
411 		}
412 	}
413 
414 	return -1;
415 }
416 
ov7725_set_fmt(const struct device * dev,enum video_endpoint_id ep,struct video_format * fmt)417 static int ov7725_set_fmt(const struct device *dev,
418 			  enum video_endpoint_id ep,
419 			  struct video_format *fmt)
420 {
421 	struct ov7725_data *drv_data = dev->data;
422 	uint8_t com10 = 0;
423 	uint16_t width, height;
424 	uint16_t hstart, vstart, hsize;
425 	int ret;
426 
427 	/* we only support one format for now (VGA RGB565) */
428 	if (fmt->pixelformat != VIDEO_PIX_FMT_RGB565 || fmt->height != 480 ||
429 	    fmt->width != 640) {
430 		return -ENOTSUP;
431 	}
432 
433 	width = fmt->width;
434 	height = fmt->height;
435 
436 	if (!memcmp(&drv_data->fmt, fmt, sizeof(drv_data->fmt))) {
437 		/* nothing to do */
438 		return 0;
439 	}
440 
441 	drv_data->fmt = *fmt;
442 
443 	/* Configure Sensor */
444 	ret = ov7725_write_all(dev, ov7725_init_reg_tb,
445 				ARRAY_SIZE(ov7725_init_reg_tb));
446 	if (ret) {
447 		LOG_ERR("Unable to write ov7725 config");
448 		return ret;
449 	}
450 
451 	/* Set clock : framerate 30fps, input clock 24M*/
452 	ov7725_set_clock(dev, 30, 24000000);
453 
454 	/* Set output format */
455 	for (uint8_t i = 0; i < ARRAY_SIZE(ov7725_pf_configs); i++) {
456 		if (ov7725_pf_configs[i].pixel_format == fmt->pixelformat) {
457 			ret =  ov7725_modify_reg(dev,
458 						OV7725_COM7,
459 						0x1FU,
460 						ov7725_pf_configs[i].com7);
461 			if (ret) {
462 				LOG_ERR("Unable to write ov7725 pixel format");
463 				return ret;
464 			}
465 		}
466 	}
467 
468 	ov7725_modify_reg(dev, OV7725_COM7, (1 << 5), (0 << 5));
469 
470 	com10 |= OV7725_COM10_VSYNC_NEG_MASK;
471 	ov7725_write_reg(dev, OV7725_COM10, com10);
472 
473 	/* Don't swap output MSB/LSB. */
474 	ov7725_write_reg(dev, OV7725_COM3, 0x00);
475 
476 	/*
477 	 * Output drive capability
478 	 * 0: 1X
479 	 * 1: 2X
480 	 * 2: 3X
481 	 * 3: 4X
482 	 */
483 	ov7725_modify_reg(dev, OV7725_COM2, 0x03, 0x03);
484 
485 	/* Resolution and timing. */
486 	hstart = 0x22U << 2U;
487 	vstart = 0x07U << 1U;
488 	hsize = width + 16U;
489 
490 	/* Set the window size. */
491 	ov7725_write_reg(dev, OV7725_HSTART, hstart >> 2U);
492 	ov7725_write_reg(dev, OV7725_HSIZE, hsize >> 2U);
493 	ov7725_write_reg(dev, OV7725_VSTART, vstart >> 1U);
494 	ov7725_write_reg(dev, OV7725_VSIZE, height >> 1U);
495 	ov7725_write_reg(dev, OV7725_HOUTSIZE, width >> 2U);
496 	ov7725_write_reg(dev, OV7725_VOUTSIZE, height >> 1U);
497 	ov7725_write_reg(dev, OV7725_HREF,
498 			 ((vstart & 1U) << 6U) |
499 			 ((hstart & 3U) << 4U) |
500 			 ((height & 1U) << 2U) |
501 			 ((hsize & 3U) << 0U));
502 	return ov7725_write_reg(dev, OV7725_EXHCH,
503 					((height & 1U) << 2U) |
504 					((width & 3U) << 0U));
505 }
506 
ov7725_get_fmt(const struct device * dev,enum video_endpoint_id ep,struct video_format * fmt)507 static int ov7725_get_fmt(const struct device *dev,
508 			  enum video_endpoint_id ep,
509 			  struct video_format *fmt)
510 {
511 	struct ov7725_data *drv_data = dev->data;
512 
513 	*fmt = drv_data->fmt;
514 
515 	return 0;
516 }
517 
ov7725_stream_start(const struct device * dev)518 static int ov7725_stream_start(const struct device *dev)
519 {
520 	return 0;
521 }
522 
ov7725_stream_stop(const struct device * dev)523 static int ov7725_stream_stop(const struct device *dev)
524 {
525 	return 0;
526 }
527 
528 static const struct video_format_cap fmts[] = {
529 	{
530 		.pixelformat = VIDEO_PIX_FMT_RGB565,
531 		.width_min = 640,
532 		.width_max = 640,
533 		.height_min = 480,
534 		.height_max = 480,
535 		.width_step = 0,
536 		.height_step = 0,
537 	},
538 	{ 0 }
539 };
540 
ov7725_get_caps(const struct device * dev,enum video_endpoint_id ep,struct video_caps * caps)541 static int ov7725_get_caps(const struct device *dev,
542 			   enum video_endpoint_id ep,
543 			   struct video_caps *caps)
544 {
545 	caps->format_caps = fmts;
546 	return 0;
547 }
548 
549 static const struct video_driver_api ov7725_driver_api = {
550 	.set_format = ov7725_set_fmt,
551 	.get_format = ov7725_get_fmt,
552 	.get_caps = ov7725_get_caps,
553 	.stream_start = ov7725_stream_start,
554 	.stream_stop = ov7725_stream_stop,
555 };
556 
ov7725_init(const struct device * dev)557 static int ov7725_init(const struct device *dev)
558 {
559 	struct ov7725_data *drv_data = dev->data;
560 	struct video_format fmt;
561 	uint8_t pid, ver;
562 	int ret;
563 
564 
565 	if (drv_data->reset_gpio) {
566 		ret = gpio_pin_configure(drv_data->reset_gpio,
567 					 drv_data->reset_pin,
568 					 GPIO_OUTPUT_ACTIVE |
569 					 drv_data->reset_flags);
570 		if (ret) {
571 			return ret;
572 		}
573 
574 		gpio_pin_set(drv_data->reset_gpio,
575 			     drv_data->reset_pin,
576 			     0);
577 		k_sleep(K_MSEC(1));
578 		gpio_pin_set(drv_data->reset_gpio,
579 			     drv_data->reset_pin,
580 			     1);
581 		k_sleep(K_MSEC(1));
582 	}
583 
584 	/* Identify the device. */
585 	ret = ov7725_read_reg(dev, OV7725_PID, &pid);
586 	if (ret) {
587 		LOG_ERR("Unable to read PID");
588 		return -ENODEV;
589 	}
590 
591 	ret = ov7725_read_reg(dev, OV7725_VER, &ver);
592 	if (ret) {
593 		LOG_ERR("Unable to read VER");
594 		return -ENODEV;
595 	}
596 
597 	if (OV7725_REVISION != (((uint32_t)pid << 8U) | (uint32_t)ver)) {
598 		LOG_ERR("OV7725 Get Vision fail\n");
599 		return -ENODEV;
600 	}
601 
602 	/* Device identify OK, perform software reset. */
603 	ov7725_write_reg(dev, OV7725_COM7, 0x80);
604 
605 	k_sleep(K_MSEC(2));
606 
607 	/* set default/init format VGA RGB565 */
608 	fmt.pixelformat = VIDEO_PIX_FMT_RGB565;
609 	fmt.width = 640;
610 	fmt.height = 480;
611 	fmt.pitch = 640 * 2;
612 	ret = ov7725_set_fmt(dev, VIDEO_EP_OUT, &fmt);
613 	if (ret) {
614 		LOG_ERR("Unable to configure default format");
615 		return -EIO;
616 	}
617 
618 	return 0;
619 }
620 
621 /* Unique Instance */
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 	struct ov7725_data *drv_data = dev->data;
627 	char *gpio_name = DT_INST_GPIO_LABEL(0, reset_gpios);
628 
629 	drv_data->reset_pin = DT_INST_GPIO_PIN(0, reset_gpios),
630 	drv_data->reset_flags = DT_INST_GPIO_FLAGS(0, reset_gpios),
631 
632 	drv_data->i2c = device_get_binding(DT_INST_BUS_LABEL(0));
633 	if (drv_data->i2c == NULL) {
634 		LOG_ERR("Failed to get pointer to %s device!",
635 			DT_INST_LABEL(0));
636 		return -EINVAL;
637 	}
638 
639 	if (gpio_name) {
640 		drv_data->reset_gpio = device_get_binding(gpio_name);
641 		if (drv_data->reset_gpio == NULL) {
642 			LOG_ERR("Failed to get pointer to %s device!",
643 				gpio_name);
644 		}
645 	}
646 
647 	drv_data->i2c_addr = DT_INST_REG_ADDR(0);
648 
649 	return ov7725_init(dev);
650 }
651 
652 DEVICE_DT_INST_DEFINE(0, &ov7725_init_0, NULL,
653 		    &ov7725_data_0, NULL,
654 		    POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
655 		    &ov7725_driver_api);
656