1 /*
2  * Copyright 2017-2018, 2021 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_video_common.h"
10 #include "fsl_camera.h"
11 #include "fsl_camera_device.h"
12 #include "fsl_mt9m114.h"
13 
14 /*******************************************************************************
15  * Definitions
16  ******************************************************************************/
17 
18 #define MT9M114_DelayMs(ms) VIDEO_DelayMs(ms)
19 #define MT9M114_Write(handle, reg, size, value)                                                          \
20     VIDEO_I2C_WriteReg(MT9M114_I2C_ADDR, kVIDEO_RegAddr16Bit, (reg), (video_reg_width_t)(size), (value), \
21                        ((mt9m114_resource_t *)((handle)->resource))->i2cSendFunc)
22 #define MT9M114_Read(handle, reg, size, value)                                                          \
23     VIDEO_I2C_ReadReg(MT9M114_I2C_ADDR, kVIDEO_RegAddr16Bit, (reg), (video_reg_width_t)(size), (value), \
24                       ((mt9m114_resource_t *)((handle)->resource))->i2cReceiveFunc)
25 #define MT9M114_Modify(handle, reg, size, clrMask, value)                                                            \
26     VIDEO_I2C_ModifyReg(MT9M114_I2C_ADDR, kVIDEO_RegAddr16Bit, (reg), (video_reg_width_t)(size), (clrMask), (value), \
27                         ((mt9m114_resource_t *)((handle)->resource))->i2cReceiveFunc,                                \
28                         ((mt9m114_resource_t *)((handle)->resource))->i2cSendFunc)
29 
30 typedef struct _mt9m114_reg
31 {
32     uint16_t reg;
33     uint8_t size;
34     uint32_t value;
35 } mt9m114_reg_t;
36 
37 /*******************************************************************************
38  * Prototypes
39  ******************************************************************************/
40 status_t MT9M114_Init(camera_device_handle_t *handle, const camera_config_t *config);
41 status_t MT9M114_Deinit(camera_device_handle_t *handle);
42 status_t MT9M114_Start(camera_device_handle_t *handle);
43 status_t MT9M114_Stop(camera_device_handle_t *handle);
44 status_t MT9M114_Control(camera_device_handle_t *handle, camera_device_cmd_t cmd, int32_t arg);
45 status_t MT9M114_InitExt(camera_device_handle_t *handle, const camera_config_t *config, const void *specialConfig);
46 
47 /*******************************************************************************
48  * Variables
49  ******************************************************************************/
50 const camera_device_operations_t mt9m114_ops = {
51     .init     = MT9M114_Init,
52     .deinit   = MT9M114_Deinit,
53     .start    = MT9M114_Start,
54     .stop     = MT9M114_Stop,
55     .control  = MT9M114_Control,
56     .init_ext = MT9M114_InitExt,
57 };
58 
59 static const mt9m114_reg_t mt9m114_720p[] = {
60     {MT9M114_VAR_CAM_SENSOR_CFG_Y_ADDR_START, 2, 0x007C},     /* cam_sensor_cfg_y_addr_start = 124 */
61     {MT9M114_VAR_CAM_SENSOR_CFG_X_ADDR_START, 2, 0x0004},     /* cam_sensor_cfg_x_addr_start = 4 */
62     {MT9M114_VAR_CAM_SENSOR_CFG_Y_ADDR_END, 2, 0x0353},       /* cam_sensor_cfg_y_addr_end = 851 */
63     {MT9M114_VAR_CAM_SENSOR_CFG_X_ADDR_END, 2, 0x050B},       /* cam_sensor_cfg_x_addr_end = 1291 */
64     {MT9M114_VAR_CAM_SENSOR_CFG_CPIPE_LAST_ROW, 2, 0x02D3},   /* cam_sensor_cfg_cpipe_last_row = 723 */
65     {MT9M114_VAR_CAM_CROP_WINDOW_WIDTH, 2, 0x0500},           /* cam_crop_window_width = 1280 */
66     {MT9M114_VAR_CAM_CROP_WINDOW_HEIGHT, 2, 0x02D0},          /* cam_crop_window_height = 720 */
67     {MT9M114_VAR_CAM_OUTPUT_WIDTH, 2, 0x0500},                /* cam_output_width = 1280 */
68     {MT9M114_VAR_CAM_OUTPUT_HEIGHT, 2, 0x02D0},               /* cam_output_height = 720 */
69     {MT9M114_VAR_CAM_STAT_AWB_CLIP_WINDOW_XEND, 2, 0x04FF},   /* cam_stat_awb_clip_window_xend = 1279 */
70     {MT9M114_VAR_CAM_STAT_AWB_CLIP_WINDOW_YEND, 2, 0x02CF},   /* cam_stat_awb_clip_window_yend = 719 */
71     {MT9M114_VAR_CAM_STAT_AE_INITIAL_WINDOW_XEND, 2, 0x00FF}, /* cam_stat_ae_initial_window_xend = 255 */
72     {MT9M114_VAR_CAM_STAT_AE_INITIAL_WINDOW_YEND, 2, 0x008F}, /* cam_stat_ae_initial_window_yend = 143 */
73 };
74 
75 static const mt9m114_reg_t mt9m114_480_272[] = {
76     {MT9M114_VAR_CAM_SENSOR_CFG_Y_ADDR_START, 2, 0x00D4},     /* cam_sensor_cfg_y_addr_start = 212 */
77     {MT9M114_VAR_CAM_SENSOR_CFG_X_ADDR_START, 2, 0x00A4},     /* cam_sensor_cfg_x_addr_start = 164 */
78     {MT9M114_VAR_CAM_SENSOR_CFG_Y_ADDR_END, 2, 0x02FB},       /* cam_sensor_cfg_y_addr_end = 763 */
79     {MT9M114_VAR_CAM_SENSOR_CFG_X_ADDR_END, 2, 0x046B},       /* cam_sensor_cfg_x_addr_end = 1131 */
80     {MT9M114_VAR_CAM_SENSOR_CFG_CPIPE_LAST_ROW, 2, 0x0223},   /* cam_sensor_cfg_cpipe_last_row = 547 */
81     {MT9M114_VAR_CAM_CROP_WINDOW_WIDTH, 2, 0x03C0},           /* cam_crop_window_width = 960 */
82     {MT9M114_VAR_CAM_CROP_WINDOW_HEIGHT, 2, 0x0220},          /* cam_crop_window_height = 544 */
83     {MT9M114_VAR_CAM_OUTPUT_WIDTH, 2, 0x01E0},                /* cam_output_width = 480 */
84     {MT9M114_VAR_CAM_OUTPUT_HEIGHT, 2, 0x0110},               /* cam_output_height = 272 */
85     {MT9M114_VAR_CAM_STAT_AWB_CLIP_WINDOW_XEND, 2, 0x01DF},   /* cam_stat_awb_clip_window_xend = 479 */
86     {MT9M114_VAR_CAM_STAT_AWB_CLIP_WINDOW_YEND, 2, 0x010F},   /* cam_stat_awb_clip_window_yend = 271 */
87     {MT9M114_VAR_CAM_STAT_AE_INITIAL_WINDOW_XEND, 2, 0x005F}, /* cam_stat_ae_initial_window_xend = 95 */
88     {MT9M114_VAR_CAM_STAT_AE_INITIAL_WINDOW_YEND, 2, 0x0035}, /* cam_stat_ae_initial_window_yend = 53 */
89 };
90 
91 static const mt9m114_reg_t mt9m114InitConfig[] = {
92     {MT9M114_REG_LOGICAL_ADDRESS_ACCESS, 2u, 0x1000},
93     /* PLL Fout = (Fin * 2 * m) / ((n + 1) * (p + 1)) */
94     {MT9M114_VAR_CAM_SYSCTL_PLL_ENABLE, 1u, 0x01},        /*  cam_sysctl_pll_enable = 1 */
95     {MT9M114_VAR_CAM_SYSCTL_PLL_DIVIDER_M_N, 2u, 0x0120}, /*  cam_sysctl_pll_divider_m_n = 288 */
96     {MT9M114_VAR_CAM_SYSCTL_PLL_DIVIDER_P, 2u, 0x0700},   /*  cam_sysctl_pll_divider_p = 1792 */
97     {MT9M114_VAR_CAM_SENSOR_CFG_PIXCLK, 4u, 0x2DC6C00},   /*  cam_sensor_cfg_pixclk = 48000000 */
98     {0x316A, 2, 0x8270}, /*  auto txlo_row for hot pixel and linear full well optimization */
99     {0x316C, 2, 0x8270}, /*  auto txlo for hot pixel and linear full well optimization */
100     {0x3ED0, 2, 0x2305}, /*  eclipse setting, ecl range=1, ecl value=2, ivln=3 */
101     {0x3ED2, 2, 0x77CF}, /*  TX_hi=12 */
102     {0x316E, 2, 0x8202}, /*  auto ecl , threshold 2x, ecl=0 at high gain, ecl=2 for low gain */
103     {0x3180, 2, 0x87FF}, /*  enable delta dark */
104     {0x30D4, 2, 0x6080}, /*  disable column correction due to AE oscillation problem */
105     {0xA802, 2, 0x0008}, /*  RESERVED_AE_TRACK_02 */
106     {0x3E14, 2, 0xFF39}, /*  Enabling pixout clamping to VAA during ADC streaming to solve column band issue */
107     {MT9M114_VAR_CAM_SENSOR_CFG_ROW_SPEED, 2u, 0x0001},           /*  cam_sensor_cfg_row_speed = 1 */
108     {MT9M114_VAR_CAM_SENSOR_CFG_FINE_INTEG_TIME_MIN, 2u, 0x00DB}, /*  cam_sensor_cfg_fine_integ_time_min = 219 */
109     {MT9M114_VAR_CAM_SENSOR_CFG_FINE_INTEG_TIME_MAX, 2u, 0x07C2}, /*  cam_sensor_cfg_fine_integ_time_max = 1986 */
110     {MT9M114_VAR_CAM_SENSOR_CFG_FRAME_LENGTH_LINES, 2u, 0x02FE},  /*  cam_sensor_cfg_frame_length_lines = 766 */
111     {MT9M114_VAR_CAM_SENSOR_CFG_LINE_LENGTH_PCK, 2u, 0x0845},     /*  cam_sensor_cfg_line_length_pck = 2117 */
112     {MT9M114_VAR_CAM_SENSOR_CFG_FINE_CORRECTION, 2u, 0x0060},     /*  cam_sensor_cfg_fine_correction = 96 */
113     {MT9M114_VAR_CAM_SENSOR_CFG_REG_0_DATA, 2u, 0x0020},          /*  cam_sensor_cfg_reg_0_data = 32 */
114     {MT9M114_VAR_CAM_SENSOR_CONTROL_READ_MODE, 2u, 0x0000},       /*  cam_sensor_control_read_mode = 0 */
115     {MT9M114_VAR_CAM_CROP_WINDOW_XOFFSET, 2u, 0x0000},            /*  cam_crop_window_xoffset = 0 */
116     {MT9M114_VAR_CAM_CROP_WINDOW_YOFFSET, 2u, 0x0000},            /*  cam_crop_window_yoffset = 0 */
117     {MT9M114_VAR_CAM_CROP_CROPMODE, 1u, 0x03},                    /*  cam_crop_cropmode = 3 */
118     {MT9M114_VAR_CAM_AET_AEMODE, 1u, 0x00},                       /*  cam_aet_aemode = 0 */
119     {MT9M114_VAR_CAM_AET_MAX_FRAME_RATE, 2u, 0x1D9A},             /*  cam_aet_max_frame_rate = 7578 */
120     {MT9M114_VAR_CAM_AET_MIN_FRAME_RATE, 2u, 0x1D9A},             /*  cam_aet_min_frame_rate = 7578 */
121     {MT9M114_VAR_CAM_STAT_AWB_CLIP_WINDOW_XSTART, 2u, 0x0000},    /*  cam_stat_awb_clip_window_xstart = 0 */
122     {MT9M114_VAR_CAM_STAT_AWB_CLIP_WINDOW_YSTART, 2u, 0x0000},    /*  cam_stat_awb_clip_window_ystart = 0 */
123     {MT9M114_VAR_CAM_STAT_AE_INITIAL_WINDOW_XSTART, 2u, 0x0000},  /*  cam_stat_ae_initial_window_xstart = 0 */
124     {MT9M114_VAR_CAM_STAT_AE_INITIAL_WINDOW_YSTART, 2u, 0x0000},  /*  cam_stat_ae_initial_window_ystart = 0 */
125     {MT9M114_REG_PAD_SLEW, 2u, 0x0777},                           /*  Pad slew rate */
126     {MT9M114_VAR_CAM_OUTPUT_FORMAT_YUV, 2u, 0x0038},              /*  Must set cam_output_format_yuv_clip for CSI */
127 };
128 
129 /*******************************************************************************
130  * Code
131  ******************************************************************************/
132 
MT9M114_MultiWrite(camera_device_handle_t * handle,const mt9m114_reg_t regs[],uint32_t num)133 static status_t MT9M114_MultiWrite(camera_device_handle_t *handle, const mt9m114_reg_t regs[], uint32_t num)
134 {
135     status_t status = kStatus_Success;
136 
137     for (uint32_t i = 0; i < num; i++)
138     {
139         status = MT9M114_Write(handle, regs[i].reg, regs[i].size, regs[i].value);
140 
141         if (kStatus_Success != status)
142         {
143             break;
144         }
145     }
146 
147     return status;
148 }
149 
MT9M114_SoftwareReset(camera_device_handle_t * handle)150 static status_t MT9M114_SoftwareReset(camera_device_handle_t *handle)
151 {
152     status_t status;
153 
154     status = MT9M114_Modify(handle, MT9M114_REG_RESET_AND_MISC_CONTROL, 2u, 0x01, 0x01);
155     if (kStatus_Success != status)
156     {
157         return status;
158     }
159 
160     MT9M114_DelayMs(1);
161 
162     status = MT9M114_Modify(handle, MT9M114_REG_RESET_AND_MISC_CONTROL, 2u, 0x01, 0x00);
163     if (kStatus_Success != status)
164     {
165         return status;
166     }
167 
168     MT9M114_DelayMs(45);
169 
170     return kStatus_Success;
171 }
172 
173 /*
174  * Set state, the parameter nextState could be
175  *
176  * MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE
177  * MT9M114_SYS_STATE_START_STREAMING
178  * MT9M114_SYS_STATE_ENTER_SUSPEND
179  * MT9M114_SYS_STATE_ENTER_STANDBY
180  * MT9M114_SYS_STATE_LEAVE_STANDBY
181  */
MT9M114_SetState(camera_device_handle_t * handle,uint16_t nextState)182 static status_t MT9M114_SetState(camera_device_handle_t *handle, uint16_t nextState)
183 {
184     status_t status;
185     uint16_t value = 0U;
186 
187     /* Set the desired next state. */
188     status = MT9M114_Write(handle, MT9M114_VAR_SYSMGR_NEXT_STATE, 1u, nextState);
189     if (kStatus_Success != status)
190     {
191         return status;
192     }
193 
194     /* Check that the FW is ready to accept a new command. */
195     while (true)
196     {
197         status = MT9M114_Read(handle, MT9M114_REG_COMMAND_REGISTER, 2u, &value);
198         if (kStatus_Success != status)
199         {
200             return status;
201         }
202 
203         if (0U == (value & MT9M114_COMMAND_SET_STATE))
204         {
205             break;
206         }
207     }
208 
209     /* Issue the Set State command. */
210     status = MT9M114_Write(handle, MT9M114_REG_COMMAND_REGISTER, 2u, MT9M114_COMMAND_SET_STATE | MT9M114_COMMAND_OK);
211     if (kStatus_Success != status)
212     {
213         return status;
214     }
215 
216     /* Wait for the FW to complete the command. */
217     while (true)
218     {
219         MT9M114_DelayMs(1);
220         status = MT9M114_Read(handle, MT9M114_REG_COMMAND_REGISTER, 2u, &value);
221         if (kStatus_Success != status)
222         {
223             return status;
224         }
225 
226         if (0U == (value & MT9M114_COMMAND_SET_STATE))
227         {
228             break;
229         }
230     }
231 
232     /* Check the 'OK' bit to see if the command was successful. */
233     status = MT9M114_Read(handle, MT9M114_REG_COMMAND_REGISTER, 2u, &value);
234     if (kStatus_Success != status)
235     {
236         return status;
237     }
238 
239     if (0U == (value & MT9M114_COMMAND_OK))
240     {
241         return kStatus_Fail;
242     }
243 
244     return kStatus_Success;
245 }
246 
MT9M114_Init(camera_device_handle_t * handle,const camera_config_t * config)247 status_t MT9M114_Init(camera_device_handle_t *handle, const camera_config_t *config)
248 {
249     status_t status;
250     uint16_t chip_id      = 0;
251     uint16_t outputFormat = 0;
252 
253     mt9m114_resource_t *resource = (mt9m114_resource_t *)(handle->resource);
254 
255     if ((kCAMERA_InterfaceGatedClock != config->interface) && (kCAMERA_InterfaceNonGatedClock != config->interface) &&
256         (kCAMERA_InterfaceCCIR656 != config->interface))
257     {
258         return kStatus_InvalidArgument;
259     }
260 
261     /* Only support 480 * 272 and 720P. */
262     if (((uint32_t)kVIDEO_Resolution720P != config->resolution) &&
263         (FSL_VIDEO_RESOLUTION(480, 272) != config->resolution))
264     {
265         return kStatus_InvalidArgument;
266     }
267 
268     /* Only support 30 fps now. */
269     if (30U != config->framePerSec)
270     {
271         return kStatus_InvalidArgument;
272     }
273 
274     /* Only support RGB565 and YUV422 */
275     if ((kVIDEO_PixelFormatRGB565 != config->pixelFormat) && (kVIDEO_PixelFormatYUYV != config->pixelFormat) &&
276         (kVIDEO_PixelFormatRAW8 != config->pixelFormat))
277     {
278         return kStatus_InvalidArgument;
279     }
280 
281     /* The input clock (EXTCLK) must be 24MHz. */
282     if (24000000U != resource->inputClockFreq_Hz)
283     {
284         return kStatus_InvalidArgument;
285     }
286 
287     /* Polarity check */
288     if (config->controlFlags !=
289         ((uint32_t)kCAMERA_HrefActiveHigh | (uint32_t)kCAMERA_DataLatchOnRisingEdge | (uint32_t)kCAMERA_VsyncActiveLow))
290     {
291         return kStatus_InvalidArgument;
292     }
293 
294     resource->pullResetPin(false); /* Reset pin low. */
295     MT9M114_DelayMs(50);           /* Delay at least 50 ms. */
296     resource->pullResetPin(true);  /* Reset pin high. */
297     MT9M114_DelayMs(45);           /* Delay typically 44.5 ms. */
298 
299     /* Identify the device. */
300     status = MT9M114_Read(handle, MT9M114_REG_CHIP_ID, 2u, &chip_id);
301     if (kStatus_Success != status)
302     {
303         return status;
304     }
305     if (MT9M114_CHIP_ID != chip_id)
306     {
307         return kStatus_Fail;
308     }
309 
310     /* SW reset. */
311     status = MT9M114_SoftwareReset(handle);
312     if (kStatus_Success != status)
313     {
314         return status;
315     }
316 
317     status = MT9M114_MultiWrite(handle, mt9m114InitConfig, ARRAY_SIZE(mt9m114InitConfig));
318     if (kStatus_Success != status)
319     {
320         return status;
321     }
322 
323     /* Pixel format. */
324     if (kVIDEO_PixelFormatRGB565 == config->pixelFormat)
325     {
326         outputFormat |= ((1U << 8U) | (1U << 1U));
327     }
328     else if (kVIDEO_PixelFormatRAW8 == config->pixelFormat)
329     {
330         outputFormat |= (((uint16_t)2U << 8U) | ((uint16_t)3U << 10U));
331     }
332     else
333     {
334         /* Empty. */
335     }
336 
337     if (kCAMERA_InterfaceCCIR656 == config->interface)
338     {
339         outputFormat |= (1U << 3U);
340     }
341 
342     status = MT9M114_Write(handle, MT9M114_VAR_CAM_OUTPUT_FORMAT, 2, outputFormat);
343     if (kStatus_Success != status)
344     {
345         return status;
346     }
347 
348     if (kCAMERA_InterfaceNonGatedClock == config->interface)
349     {
350         status = MT9M114_Write(handle, MT9M114_VAR_CAM_PORT_OUTPUT_CONTROL, 2, 0x8020);
351     }
352     else
353     {
354         status = MT9M114_Write(handle, MT9M114_VAR_CAM_PORT_OUTPUT_CONTROL, 2, 0x8000);
355     }
356 
357     if (kStatus_Success != status)
358     {
359         return status;
360     }
361 
362     /* Resolution */
363     if (config->resolution == FSL_VIDEO_RESOLUTION(480, 272))
364     {
365         status = MT9M114_MultiWrite(handle, mt9m114_480_272, ARRAY_SIZE(mt9m114_480_272));
366     }
367     else
368     {
369         status = MT9M114_MultiWrite(handle, mt9m114_720p, ARRAY_SIZE(mt9m114_720p));
370     }
371 
372     if (kStatus_Success != status)
373     {
374         return status;
375     }
376 
377     /* Execute Change-Config command. */
378     return MT9M114_SetState(handle, MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE);
379 }
380 
MT9M114_Deinit(camera_device_handle_t * handle)381 status_t MT9M114_Deinit(camera_device_handle_t *handle)
382 {
383     ((mt9m114_resource_t *)(handle->resource))->pullResetPin(false);
384 
385     return kStatus_Success;
386 }
387 
MT9M114_Start(camera_device_handle_t * handle)388 status_t MT9M114_Start(camera_device_handle_t *handle)
389 {
390     return MT9M114_SetState(handle, MT9M114_SYS_STATE_START_STREAMING);
391 }
392 
MT9M114_Stop(camera_device_handle_t * handle)393 status_t MT9M114_Stop(camera_device_handle_t *handle)
394 {
395     return MT9M114_SetState(handle, MT9M114_SYS_STATE_ENTER_SUSPEND);
396 }
397 
MT9M114_Control(camera_device_handle_t * handle,camera_device_cmd_t cmd,int32_t arg)398 status_t MT9M114_Control(camera_device_handle_t *handle, camera_device_cmd_t cmd, int32_t arg)
399 {
400     return kStatus_InvalidArgument;
401 }
402 
MT9M114_InitExt(camera_device_handle_t * handle,const camera_config_t * config,const void * specialConfig)403 status_t MT9M114_InitExt(camera_device_handle_t *handle, const camera_config_t *config, const void *specialConfig)
404 {
405     return MT9M114_Init(handle, config);
406 }
407