1 /*
2  * Copyright (c) 2019, Linaro Limited
3  * Copyright 2024 NXP
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #define DT_DRV_COMPAT aptina_mt9m114
9 
10 #include <zephyr/kernel.h>
11 #include <zephyr/device.h>
12 #include <zephyr/logging/log.h>
13 #include <zephyr/sys/byteorder.h>
14 #include <zephyr/drivers/video.h>
15 #include <zephyr/drivers/video-controls.h>
16 #include <zephyr/drivers/i2c.h>
17 
18 LOG_MODULE_REGISTER(video_mt9m114, CONFIG_VIDEO_LOG_LEVEL);
19 
20 #define MT9M114_CHIP_ID_VAL 0x2481
21 
22 /* Sysctl registers */
23 #define MT9M114_CHIP_ID                    0x0000
24 #define MT9M114_COMMAND_REGISTER           0x0080
25 #define MT9M114_COMMAND_REGISTER_SET_STATE (1 << 1)
26 #define MT9M114_COMMAND_REGISTER_OK        (1 << 15)
27 #define MT9M114_RST_AND_MISC_CONTROL       0x001A
28 
29 /* Camera Control registers */
30 #define MT9M114_CAM_SENSOR_CFG_Y_ADDR_START     0xC800
31 #define MT9M114_CAM_SENSOR_CFG_X_ADDR_START     0xC802
32 #define MT9M114_CAM_SENSOR_CFG_Y_ADDR_END       0xC804
33 #define MT9M114_CAM_SENSOR_CFG_X_ADDR_END       0xC806
34 #define MT9M114_CAM_SENSOR_CFG_CPIPE_LAST_ROW   0xC818
35 #define MT9M114_CAM_SENSOR_CTRL_READ_MODE       0xC834
36 #define MT9M114_CAM_CROP_WINDOW_WIDTH           0xC858
37 #define MT9M114_CAM_CROP_WINDOW_HEIGHT          0xC85A
38 #define MT9M114_CAM_OUTPUT_WIDTH                0xC868
39 #define MT9M114_CAM_OUTPUT_HEIGHT               0xC86A
40 #define MT9M114_CAM_OUTPUT_FORMAT               0xC86C
41 #define MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XEND   0xC918
42 #define MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YEND   0xC91A
43 #define MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XEND 0xC920
44 #define MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YEND 0xC922
45 
46 /* System Manager registers */
47 #define MT9M114_SYSMGR_NEXT_STATE 0xDC00
48 
49 /* System States */
50 #define MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE 0x28
51 #define MT9M114_SYS_STATE_START_STREAMING     0x34
52 #define MT9M114_SYS_STATE_ENTER_SUSPEND       0x40
53 
54 /* Camera output format */
55 #define MT9M114_CAM_OUTPUT_FORMAT_FORMAT_YUV (0 << 8)
56 #define MT9M114_CAM_OUTPUT_FORMAT_FORMAT_RGB (1 << 8)
57 
58 /* Camera control masks */
59 #define MT9M114_CAM_SENSOR_CTRL_HORZ_FLIP_EN BIT(0)
60 #define MT9M114_CAM_SENSOR_CTRL_VERT_FLIP_EN BIT(1)
61 
62 struct mt9m114_config {
63 	struct i2c_dt_spec i2c;
64 };
65 
66 struct mt9m114_data {
67 	struct video_format fmt;
68 };
69 
70 struct mt9m114_reg {
71 	uint16_t addr;
72 	uint16_t value_size;
73 	uint32_t value;
74 };
75 
76 struct mt9m114_resolution_config {
77 	uint16_t width;
78 	uint16_t height;
79 	struct mt9m114_reg *params;
80 };
81 
82 static struct mt9m114_reg mt9m114_init_config[] = {
83 	{0x098E, 2, 0x1000},    /* LOGICAL_ADDRESS_ACCESS */
84 	{0xC97E, 1, 0x01},      /* CAM_SYSCTL_PLL_ENABLE */
85 	{0xC980, 2, 0x0120},    /* CAM_SYSCTL_PLL_DIVIDER_M_N = 288 */
86 	{0xC982, 2, 0x0700},    /* CAM_SYSCTL_PLL_DIVIDER_P = 1792 */
87 	{0xC808, 4, 0x2DC6C00}, /* CAM_SENSOR_CFG_PIXCLK = 48 Mhz */
88 	{0x316A, 2, 0x8270},    /* Auto txlo_row for hot pixel and linear full well optimization */
89 	{0x316C, 2, 0x8270},    /* Auto txlo for hot pixel and linear full well optimization */
90 	{0x3ED0, 2, 0x2305},    /* Eclipse setting, ecl range=1, ecl value=2, ivln=3 */
91 	{0x3ED2, 2, 0x77CF},    /* TX_hi = 12 */
92 	{0x316E, 2, 0x8202}, /* Auto ecl , threshold 2x, ecl=0 at high gain, ecl=2 for low gain */
93 	{0x3180, 2, 0x87FF}, /* Enable delta dark */
94 	{0x30D4, 2, 0x6080}, /* Disable column correction due to AE oscillation problem */
95 	{0xA802, 2, 0x0008}, /* RESERVED_AE_TRACK_02 */
96 	{0x3E14, 2, 0xFF39}, /* Enabling pixout clamping to VAA to solve column band issue */
97 	{0xC80C, 2, 0x0001}, /* CAM_SENSOR_CFG_ROW_SPEED */
98 	{0xC80E, 2, 0x00DB}, /* CAM_SENSOR_CFG_FINE_INTEG_TIME_MIN = 219 */
99 	{0xC810, 2, 0x07C2}, /* CAM_SENSOR_CFG_FINE_INTEG_TIME_MAX = 1986 */
100 	{0xC812, 2, 0x02FE}, /* CAM_SENSOR_CFG_FRAME_LENGTH_LINES = 766 */
101 	{0xC814, 2, 0x0845}, /* CAM_SENSOR_CFG_LINE_LENGTH_PCK = 2117 */
102 	{0xC816, 2, 0x0060}, /* CAM_SENSOR_CFG_FINE_CORRECTION = 96 */
103 	{0xC826, 2, 0x0020}, /* CAM_SENSOR_CFG_REG_0_DATA = 32 */
104 	{0xC834, 2, 0x0000}, /* CAM_SENSOR_CONTROL_READ_MODE */
105 	{0xC854, 2, 0x0000}, /* CAM_CROP_WINDOW_XOFFSET */
106 	{0xC856, 2, 0x0000}, /* CAM_CROP_WINDOW_YOFFSET */
107 	{0xC85C, 1, 0x03},   /* CAM_CROP_CROPMODE */
108 	{0xC878, 1, 0x00},   /* CAM_AET_AEMODE */
109 	{0xC88C, 2, 0x1D9A}, /* CAM_AET_MAX_FRAME_RATE = 7578 */
110 	{0xC88E, 2, 0x1D9A}, /* CAM_AET_MIN_FRAME_RATE = 7578 */
111 	{0xC914, 2, 0x0000}, /* CAM_STAT_AWB_CLIP_WINDOW_XSTART */
112 	{0xC916, 2, 0x0000}, /* CAM_STAT_AWB_CLIP_WINDOW_YSTART */
113 	{0xC91C, 2, 0x0000}, /* CAM_STAT_AE_INITIAL_WINDOW_XSTART */
114 	{0xC91E, 2, 0x0000}, /* CAM_STAT_AE_INITIAL_WINDOW_YSTART */
115 	{0x001E, 2, 0x0777}, /* REG_PAD_SLEW */
116 	{0xC86E, 2, 0x0038}, /* CAM_OUTPUT_FORMAT_YUV_CLIP for CSI */
117 	{0xC984, 2, 0x8000}, /* CAM_PORT_OUTPUT_CONTROL, for MIPI CSI-2 interface : 0x8000 */
118 	{/* NULL terminated */}};
119 
120 static struct mt9m114_reg mt9m114_480_272[] = {
121 	{MT9M114_CAM_SENSOR_CFG_Y_ADDR_START, 2, 0x00D4},     /* 212 */
122 	{MT9M114_CAM_SENSOR_CFG_X_ADDR_START, 2, 0x00A4},     /* 164 */
123 	{MT9M114_CAM_SENSOR_CFG_Y_ADDR_END, 2, 0x02FB},       /* 763 */
124 	{MT9M114_CAM_SENSOR_CFG_X_ADDR_END, 2, 0x046B},       /* 1131 */
125 	{MT9M114_CAM_SENSOR_CFG_CPIPE_LAST_ROW, 2, 0x0223},   /* 547 */
126 	{MT9M114_CAM_CROP_WINDOW_WIDTH, 2, 0x03C0},           /* 960 */
127 	{MT9M114_CAM_CROP_WINDOW_HEIGHT, 2, 0x0220},          /* 544 */
128 	{MT9M114_CAM_OUTPUT_WIDTH, 2, 0x01E0},                /* 480 */
129 	{MT9M114_CAM_OUTPUT_HEIGHT, 2, 0x0110},               /* 272 */
130 	{MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XEND, 2, 0x01DF},   /* 479 */
131 	{MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YEND, 2, 0x010F},   /* 271 */
132 	{MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XEND, 2, 0x005F}, /* 95 */
133 	{MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YEND, 2, 0x0035}, /* 53 */
134 	{/* NULL terminated */}};
135 
136 static struct mt9m114_reg mt9m114_640_480[] = {
137 	{MT9M114_CAM_SENSOR_CFG_Y_ADDR_START, 2, 0x0000},     /* 0 */
138 	{MT9M114_CAM_SENSOR_CFG_X_ADDR_START, 2, 0x0000},     /* 0 */
139 	{MT9M114_CAM_SENSOR_CFG_Y_ADDR_END, 2, 0x03CD},       /* 973 */
140 	{MT9M114_CAM_SENSOR_CFG_X_ADDR_END, 2, 0x050D},       /* 1293 */
141 	{MT9M114_CAM_SENSOR_CFG_CPIPE_LAST_ROW, 2, 0x01E3},   /* 483 */
142 	{MT9M114_CAM_CROP_WINDOW_WIDTH, 2, 0x0280},           /* 640 */
143 	{MT9M114_CAM_CROP_WINDOW_HEIGHT, 2, 0x01E0},          /* 480 */
144 	{MT9M114_CAM_OUTPUT_WIDTH, 2, 0x0280},                /* 640 */
145 	{MT9M114_CAM_OUTPUT_HEIGHT, 2, 0x01E0},               /* 480 */
146 	{MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XEND, 2, 0x027F},   /* 639 */
147 	{MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YEND, 2, 0x01DF},   /* 479 */
148 	{MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XEND, 2, 0x007F}, /* 127 */
149 	{MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YEND, 2, 0x005F}, /* 95 */
150 	{/* NULL terminated */}};
151 
152 static struct mt9m114_reg mt9m114_1280_720[] = {
153 	{MT9M114_CAM_SENSOR_CFG_Y_ADDR_START, 2, 0x007C},     /* 124 */
154 	{MT9M114_CAM_SENSOR_CFG_X_ADDR_START, 2, 0x0004},     /* 4 */
155 	{MT9M114_CAM_SENSOR_CFG_Y_ADDR_END, 2, 0x0353},       /* 851 */
156 	{MT9M114_CAM_SENSOR_CFG_X_ADDR_END, 2, 0x050B},       /* 1291 */
157 	{MT9M114_CAM_SENSOR_CFG_CPIPE_LAST_ROW, 2, 0x02D3},   /* 723 */
158 	{MT9M114_CAM_CROP_WINDOW_WIDTH, 2, 0x0500},           /* 1280 */
159 	{MT9M114_CAM_CROP_WINDOW_HEIGHT, 2, 0x02D0},          /* 720 */
160 	{MT9M114_CAM_OUTPUT_WIDTH, 2, 0x0500},                /* 1280 */
161 	{MT9M114_CAM_OUTPUT_HEIGHT, 2, 0x02D0},               /* 720 */
162 	{MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XEND, 2, 0x04FF},   /* 1279 */
163 	{MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YEND, 2, 0x02CF},   /* 719 */
164 	{MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XEND, 2, 0x00FF}, /* 255 */
165 	{MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YEND, 2, 0x008F}, /* 143 */
166 	{/* NULL terminated */}};
167 
168 static struct mt9m114_resolution_config resolutionConfigs[] = {
169 	{.width = 480, .height = 272, .params = mt9m114_480_272},
170 	{.width = 640, .height = 480, .params = mt9m114_640_480},
171 	{.width = 1280, .height = 720, .params = mt9m114_1280_720},
172 };
173 
174 #define MT9M114_VIDEO_FORMAT_CAP(width, height, format)                                            \
175 	{                                                                                          \
176 		.pixelformat = (format), .width_min = (width), .width_max = (width),               \
177 		.height_min = (height), .height_max = (height), .width_step = 0, .height_step = 0  \
178 	}
179 
180 static const struct video_format_cap fmts[] = {
181 	MT9M114_VIDEO_FORMAT_CAP(480, 272, VIDEO_PIX_FMT_RGB565),
182 	MT9M114_VIDEO_FORMAT_CAP(480, 272, VIDEO_PIX_FMT_YUYV),
183 	MT9M114_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_RGB565),
184 	MT9M114_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_YUYV),
185 	MT9M114_VIDEO_FORMAT_CAP(1280, 720, VIDEO_PIX_FMT_RGB565),
186 	MT9M114_VIDEO_FORMAT_CAP(1280, 720, VIDEO_PIX_FMT_YUYV),
187 	{0}};
188 
i2c_burst_read16_dt(const struct i2c_dt_spec * spec,uint16_t start_addr,uint8_t * buf,uint32_t num_bytes)189 static inline int i2c_burst_read16_dt(const struct i2c_dt_spec *spec, uint16_t start_addr,
190 				      uint8_t *buf, uint32_t num_bytes)
191 {
192 	uint8_t addr_buffer[2];
193 
194 	addr_buffer[1] = start_addr & 0xFF;
195 	addr_buffer[0] = start_addr >> 8;
196 	return i2c_write_read_dt(spec, addr_buffer, sizeof(addr_buffer), buf, num_bytes);
197 }
198 
i2c_burst_write16_dt(const struct i2c_dt_spec * spec,uint16_t start_addr,const uint8_t * buf,uint32_t num_bytes)199 static inline int i2c_burst_write16_dt(const struct i2c_dt_spec *spec, uint16_t start_addr,
200 				       const uint8_t *buf, uint32_t num_bytes)
201 {
202 	uint8_t addr_buffer[2];
203 	struct i2c_msg msg[2];
204 
205 	addr_buffer[1] = start_addr & 0xFF;
206 	addr_buffer[0] = start_addr >> 8;
207 	msg[0].buf = addr_buffer;
208 	msg[0].len = 2U;
209 	msg[0].flags = I2C_MSG_WRITE;
210 
211 	msg[1].buf = (uint8_t *)buf;
212 	msg[1].len = num_bytes;
213 	msg[1].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
214 
215 	return i2c_transfer_dt(spec, msg, 2);
216 }
217 
mt9m114_write_reg(const struct device * dev,uint16_t reg_addr,uint8_t reg_size,void * value)218 static int mt9m114_write_reg(const struct device *dev, uint16_t reg_addr, uint8_t reg_size,
219 			     void *value)
220 {
221 	const struct mt9m114_config *cfg = dev->config;
222 
223 	switch (reg_size) {
224 	case 2:
225 		*(uint16_t *)value = sys_cpu_to_be16(*(uint16_t *)value);
226 		break;
227 	case 4:
228 		*(uint32_t *)value = sys_cpu_to_be32(*(uint32_t *)value);
229 		break;
230 	case 1:
231 		break;
232 	default:
233 		return -ENOTSUP;
234 	}
235 
236 	return i2c_burst_write16_dt(&cfg->i2c, reg_addr, value, reg_size);
237 }
238 
mt9m114_read_reg(const struct device * dev,uint16_t reg_addr,uint8_t reg_size,void * value)239 static int mt9m114_read_reg(const struct device *dev, uint16_t reg_addr, uint8_t reg_size,
240 			    void *value)
241 {
242 	const struct mt9m114_config *cfg = dev->config;
243 	int err;
244 
245 	if (reg_size > 4) {
246 		return -ENOTSUP;
247 	}
248 
249 	err = i2c_burst_read16_dt(&cfg->i2c, reg_addr, value, reg_size);
250 	if (err) {
251 		return err;
252 	}
253 
254 	switch (reg_size) {
255 	case 2:
256 		*(uint16_t *)value = sys_be16_to_cpu(*(uint16_t *)value);
257 		break;
258 	case 4:
259 		*(uint32_t *)value = sys_be32_to_cpu(*(uint32_t *)value);
260 		break;
261 	case 1:
262 		break;
263 	default:
264 		return -ENOTSUP;
265 	}
266 
267 	return 0;
268 }
269 
mt9m114_modify_reg(const struct device * dev,const uint16_t addr,uint8_t reg_size,const uint32_t mask,const uint32_t val)270 static int mt9m114_modify_reg(const struct device *dev, const uint16_t addr,
271 			      uint8_t reg_size, const uint32_t mask, const uint32_t val)
272 {
273 	uint32_t oldVal = 0;
274 	uint32_t newVal = 0;
275 
276 	int ret = mt9m114_read_reg(dev, addr, reg_size, &oldVal);
277 
278 	if (ret) {
279 		return ret;
280 	}
281 
282 	newVal = (oldVal & ~mask) | (val & mask);
283 
284 	return mt9m114_write_reg(dev, addr, reg_size, &newVal);
285 }
286 
mt9m114_write_all(const struct device * dev,struct mt9m114_reg * reg)287 static int mt9m114_write_all(const struct device *dev, struct mt9m114_reg *reg)
288 {
289 	int i = 0;
290 
291 	while (reg[i].value_size) {
292 		int err;
293 
294 		err = mt9m114_write_reg(dev, reg[i].addr, reg[i].value_size, &reg[i].value);
295 		if (err) {
296 			return err;
297 		}
298 
299 		i++;
300 	}
301 
302 	return 0;
303 }
304 
mt9m114_software_reset(const struct device * dev)305 static int mt9m114_software_reset(const struct device *dev)
306 {
307 	int ret = mt9m114_modify_reg(dev, MT9M114_RST_AND_MISC_CONTROL, 2, 0x01, 0x01);
308 
309 	if (ret) {
310 		return ret;
311 	}
312 
313 	k_sleep(K_MSEC(1));
314 
315 	ret = mt9m114_modify_reg(dev, MT9M114_RST_AND_MISC_CONTROL, 2, 0x01, 0x00);
316 	if (ret) {
317 		return ret;
318 	}
319 
320 	k_sleep(K_MSEC(45));
321 
322 	return 0;
323 }
324 
mt9m114_set_state(const struct device * dev,uint8_t state)325 static int mt9m114_set_state(const struct device *dev, uint8_t state)
326 {
327 	uint16_t val;
328 	int err;
329 
330 	/* Set next state. */
331 	mt9m114_write_reg(dev, MT9M114_SYSMGR_NEXT_STATE, 1, &state);
332 
333 	/* Check that the FW is ready to accept a new command. */
334 	while (1) {
335 		err = mt9m114_read_reg(dev, MT9M114_COMMAND_REGISTER, 2, &val);
336 		if (err) {
337 			return err;
338 		}
339 
340 		if (!(val & MT9M114_COMMAND_REGISTER_SET_STATE)) {
341 			break;
342 		}
343 
344 		k_sleep(K_MSEC(1));
345 	}
346 
347 	/* Issue the Set State command. */
348 	val = MT9M114_COMMAND_REGISTER_SET_STATE | MT9M114_COMMAND_REGISTER_OK;
349 	mt9m114_write_reg(dev, MT9M114_COMMAND_REGISTER, 2, &val);
350 
351 	/* Wait for the FW to complete the command. */
352 	while (1) {
353 		err = mt9m114_read_reg(dev, MT9M114_COMMAND_REGISTER, 2, &val);
354 		if (err) {
355 			return err;
356 		}
357 
358 		if (!(val & MT9M114_COMMAND_REGISTER_SET_STATE)) {
359 			break;
360 		}
361 
362 		k_sleep(K_MSEC(1));
363 	}
364 
365 	/* Check the 'OK' bit to see if the command was successful. */
366 	err = mt9m114_read_reg(dev, MT9M114_COMMAND_REGISTER, 2, &val);
367 	if (err || !(val & MT9M114_COMMAND_REGISTER_OK)) {
368 		return -EIO;
369 	}
370 
371 	return 0;
372 }
373 
mt9m114_set_output_format(const struct device * dev,int pixel_format)374 static int mt9m114_set_output_format(const struct device *dev, int pixel_format)
375 {
376 	int ret = 0;
377 	uint16_t output_format;
378 
379 	if (pixel_format == VIDEO_PIX_FMT_YUYV) {
380 		output_format = (MT9M114_CAM_OUTPUT_FORMAT_FORMAT_YUV | (1U << 1U));
381 	} else if (pixel_format == VIDEO_PIX_FMT_RGB565) {
382 		output_format = (MT9M114_CAM_OUTPUT_FORMAT_FORMAT_RGB | (1U << 1U));
383 	}
384 
385 	ret = mt9m114_write_reg(dev, MT9M114_CAM_OUTPUT_FORMAT, sizeof(output_format),
386 				&output_format);
387 
388 	return ret;
389 }
390 
mt9m114_set_fmt(const struct device * dev,enum video_endpoint_id ep,struct video_format * fmt)391 static int mt9m114_set_fmt(const struct device *dev, enum video_endpoint_id ep,
392 			   struct video_format *fmt)
393 {
394 	struct mt9m114_data *drv_data = dev->data;
395 	int ret;
396 	int i = 0;
397 
398 	while (fmts[i].pixelformat) {
399 		if (fmt->pixelformat == fmts[i].pixelformat && fmt->width >= fmts[i].width_min &&
400 		    fmt->width <= fmts[i].width_max && fmt->height >= fmts[i].height_min &&
401 		    fmt->height <= fmts[i].height_max) {
402 			break;
403 		}
404 		i++;
405 	}
406 
407 	if (i == (ARRAY_SIZE(fmts) - 1)) {
408 		LOG_ERR("Unsupported pixel format or resolution");
409 		return -ENOTSUP;
410 	}
411 
412 	if (!memcmp(&drv_data->fmt, fmt, sizeof(drv_data->fmt))) {
413 		/* nothing to do */
414 		return 0;
415 	}
416 
417 	drv_data->fmt = *fmt;
418 
419 	/* Set output pixel format */
420 	ret = mt9m114_set_output_format(dev, fmt->pixelformat);
421 	if (ret) {
422 		LOG_ERR("Unable to set pixel format");
423 		return ret;
424 	}
425 
426 	/* Set output resolution */
427 	for (i = 0; i < ARRAY_SIZE(resolutionConfigs); i++) {
428 		if (fmt->width == resolutionConfigs[i].width &&
429 		    fmt->height == resolutionConfigs[i].height) {
430 			ret = mt9m114_write_all(dev, resolutionConfigs[i].params);
431 			if (ret) {
432 				LOG_ERR("Unable to set resolution");
433 				return ret;
434 			}
435 
436 			break;
437 		}
438 	}
439 
440 	/* Apply Config */
441 	return mt9m114_set_state(dev, MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE);
442 }
443 
mt9m114_get_fmt(const struct device * dev,enum video_endpoint_id ep,struct video_format * fmt)444 static int mt9m114_get_fmt(const struct device *dev, enum video_endpoint_id ep,
445 			   struct video_format *fmt)
446 {
447 	struct mt9m114_data *drv_data = dev->data;
448 
449 	*fmt = drv_data->fmt;
450 
451 	return 0;
452 }
453 
mt9m114_stream_start(const struct device * dev)454 static int mt9m114_stream_start(const struct device *dev)
455 {
456 	return mt9m114_set_state(dev, MT9M114_SYS_STATE_START_STREAMING);
457 }
458 
mt9m114_stream_stop(const struct device * dev)459 static int mt9m114_stream_stop(const struct device *dev)
460 {
461 	return mt9m114_set_state(dev, MT9M114_SYS_STATE_ENTER_SUSPEND);
462 }
463 
mt9m114_get_caps(const struct device * dev,enum video_endpoint_id ep,struct video_caps * caps)464 static int mt9m114_get_caps(const struct device *dev, enum video_endpoint_id ep,
465 			    struct video_caps *caps)
466 {
467 	caps->format_caps = fmts;
468 	return 0;
469 }
470 
mt9m114_set_ctrl(const struct device * dev,unsigned int cid,void * value)471 static int mt9m114_set_ctrl(const struct device *dev, unsigned int cid, void *value)
472 {
473 	int ret = 0;
474 
475 	switch (cid) {
476 	case VIDEO_CID_HFLIP:
477 		ret = mt9m114_modify_reg(dev, MT9M114_CAM_SENSOR_CTRL_READ_MODE, 2,
478 					MT9M114_CAM_SENSOR_CTRL_HORZ_FLIP_EN,
479 					(int)value ? MT9M114_CAM_SENSOR_CTRL_HORZ_FLIP_EN : 0);
480 		break;
481 	case VIDEO_CID_VFLIP:
482 		ret = mt9m114_modify_reg(dev, MT9M114_CAM_SENSOR_CTRL_READ_MODE, 2,
483 					MT9M114_CAM_SENSOR_CTRL_VERT_FLIP_EN,
484 					(int)value ? MT9M114_CAM_SENSOR_CTRL_VERT_FLIP_EN : 0);
485 		break;
486 	default:
487 		return -ENOTSUP;
488 	}
489 
490 	if (ret < 0) {
491 		return ret;
492 	}
493 
494 	/* Apply Config */
495 	return mt9m114_set_state(dev, MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE);
496 }
497 
498 static DEVICE_API(video, mt9m114_driver_api) = {
499 	.set_format = mt9m114_set_fmt,
500 	.get_format = mt9m114_get_fmt,
501 	.get_caps = mt9m114_get_caps,
502 	.stream_start = mt9m114_stream_start,
503 	.stream_stop = mt9m114_stream_stop,
504 	.set_ctrl = mt9m114_set_ctrl,
505 };
506 
mt9m114_init(const struct device * dev)507 static int mt9m114_init(const struct device *dev)
508 {
509 	struct video_format fmt;
510 	uint16_t val;
511 	int ret;
512 
513 	/* no power control, wait for camera ready */
514 	k_sleep(K_MSEC(100));
515 
516 	ret = mt9m114_read_reg(dev, MT9M114_CHIP_ID, sizeof(val), &val);
517 	if (ret) {
518 		LOG_ERR("Unable to read chip ID");
519 		return -ENODEV;
520 	}
521 
522 	if (val != MT9M114_CHIP_ID_VAL) {
523 		LOG_ERR("Wrong ID: %04x (exp %04x)", val, MT9M114_CHIP_ID_VAL);
524 		return -ENODEV;
525 	}
526 
527 	/* SW reset */
528 	mt9m114_software_reset(dev);
529 
530 	/* Init registers */
531 	ret = mt9m114_write_all(dev, mt9m114_init_config);
532 	if (ret) {
533 		LOG_ERR("Unable to initialize mt9m114 config");
534 		return ret;
535 	}
536 
537 	/* Set default format to 480x272 RGB565 */
538 	fmt.pixelformat = VIDEO_PIX_FMT_RGB565;
539 	fmt.width = 480;
540 	fmt.height = 272;
541 	fmt.pitch = fmt.width * 2;
542 
543 	ret = mt9m114_set_fmt(dev, VIDEO_EP_OUT, &fmt);
544 	if (ret) {
545 		LOG_ERR("Unable to configure default format");
546 		return -EIO;
547 	}
548 
549 	/* Suspend any stream */
550 	mt9m114_set_state(dev, MT9M114_SYS_STATE_ENTER_SUSPEND);
551 
552 	return 0;
553 }
554 
555 #if 1 /* Unique Instance */
556 
557 static const struct mt9m114_config mt9m114_cfg_0 = {
558 	.i2c = I2C_DT_SPEC_INST_GET(0),
559 };
560 
561 static struct mt9m114_data mt9m114_data_0;
562 
mt9m114_init_0(const struct device * dev)563 static int mt9m114_init_0(const struct device *dev)
564 {
565 	const struct mt9m114_config *cfg = dev->config;
566 
567 	if (!device_is_ready(cfg->i2c.bus)) {
568 		LOG_ERR("Bus device is not ready");
569 		return -ENODEV;
570 	}
571 
572 	return mt9m114_init(dev);
573 }
574 
575 DEVICE_DT_INST_DEFINE(0, &mt9m114_init_0, NULL, &mt9m114_data_0, &mt9m114_cfg_0, POST_KERNEL,
576 		      CONFIG_VIDEO_INIT_PRIORITY, &mt9m114_driver_api);
577 #endif
578