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, ®[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