@@ -775,6 +775,8 @@ struct gc2145_data {
775775 struct gc2145_ctrls ctrls ;
776776 struct video_format fmt ;
777777 struct video_rect crop ;
778+ uint16_t format_width ;
779+ uint16_t format_height ;
778780 uint8_t c_ratio ;
779781 uint8_t r_ratio ;
780782};
@@ -870,8 +872,7 @@ static int gc2145_set_output_format(const struct device *dev, int output_format)
870872}
871873
872874
873- static int gc2145_set_resolution (const struct device * dev , uint32_t w , uint32_t h ,
874- bool compute_ratio )
875+ static int gc2145_gc2145_set_resolution (const struct device * dev , uint32_t w , uint32_t h )
875876{
876877 const struct gc2145_config * cfg = dev -> config ;
877878 struct gc2145_data * drv_data = dev -> data ;
@@ -887,6 +888,8 @@ static int gc2145_set_resolution(const struct device *dev, uint32_t w, uint32_t
887888 if ((w == 0 ) || (h == 0 )) {
888889 return - EIO ;
889890 }
891+
892+ /* If we are called from set_format, then we compute ratio and initialize crop */
890893 drv_data -> c_ratio = RESOLUTION_UXGA_W / w ;
891894 drv_data -> r_ratio = RESOLUTION_UXGA_H / h ;
892895 if (drv_data -> c_ratio < drv_data -> r_ratio ) {
@@ -895,22 +898,35 @@ static int gc2145_set_resolution(const struct device *dev, uint32_t w, uint32_t
895898 drv_data -> c_ratio = drv_data -> r_ratio ;
896899 }
897900
901+ /* Restrict ratio to 3 for faster refresh ? */
902+ if (drv_data -> c_ratio > 3 ) {
903+ drv_data -> c_ratio = 3 ;
904+ drv_data -> r_ratio = 3 ;
905+ }
906+
898907 /* make sure we don't end up with ratio of 0 */
899908 if (drv_data -> c_ratio == 0 ) {
900909 return - EIO ;
901910 }
902911
912+ /* remember the width and height passed in */
913+ drv_data -> format_width = w ;
914+ drv_data -> format_height = h ;
915+
916+ /* Default to crop rectangle being same size as passed in resolution */
917+ drv_data -> crop .left = 0 ;
918+ drv_data -> crop .top = 0 ;
919+ drv_data -> crop .width = w ;
920+ drv_data -> crop .height = h ;
921+
922+
903923 /* Calculates the window boundaries to obtain the desired resolution */
904924
905925 win_w = w * drv_data -> c_ratio ;
906926 win_h = h * drv_data -> r_ratio ;
907927 win_x = ((UXGA_HSIZE - win_w ) / 2 );
908928 win_y = ((UXGA_VSIZE - win_h ) / 2 );
909929
910- drv_data -> crop .left = 0 ;
911- drv_data -> crop .top = 0 ;
912- drv_data -> crop .width = w ;
913- drv_data -> crop .height = h ;
914930
915931 x = (((win_w / drv_data -> c_ratio ) - w ) / 2 );
916932 y = (((win_h / drv_data -> r_ratio ) - h ) / 2 );
@@ -986,29 +1002,63 @@ static int gc2145_set_resolution(const struct device *dev, uint32_t w, uint32_t
9861002 return 0 ;
9871003}
9881004
989- static int gc2145_set_crop (const struct device * dev )
1005+ static int gc2145_set_crop (const struct device * dev , struct video_selection * sel )
9901006{
9911007 /* set the crop, start off with most of a duplicate of set resolution */
9921008 int ret ;
1009+ const struct gc2145_config * cfg = dev -> config ;
9931010 struct gc2145_data * drv_data = dev -> data ;
9941011
995- /* Calculates the window boundaries to obtain the desired resolution */
996- if ((drv_data -> fmt .width == drv_data -> crop .width ) &&
997- (drv_data -> fmt .height == drv_data -> crop .height )) {
1012+
1013+ /* Verify the passed in rectangle is valid */
1014+ if (((sel -> rect .left + sel -> rect .width ) > drv_data -> format_width ) ||
1015+ ((sel -> rect .top + sel -> rect .height ) > drv_data -> format_height )) {
1016+ LOG_INF ("(%u %u) %ux%u > %ux%u" , sel -> rect .left , sel -> rect .top ,
1017+ sel -> rect .width , sel -> rect .height ,
1018+ drv_data -> format_width , drv_data -> format_height );
1019+ return - EINVAL ;
1020+ }
1021+
1022+ /* if rectangle passed in is same as current, simply return */
1023+ if (memcmp ((void * )& drv_data -> crop , (void * )& sel -> rect , sizeof (struct video_rect )) == 0 ) {
9981024 return 0 ;
9991025 }
10001026
1001- LOG_DBG ("set_res: %u %u ratios: %u %u" , drv_data -> crop .width , drv_data -> crop .height ,
1002- drv_data -> c_ratio , drv_data -> r_ratio );
1003- ret = gc2145_set_resolution (dev , drv_data -> crop .width , drv_data -> crop .height , false);
1004- if (ret == 0 ) {
1005- /* enqueue/dequeue depend on this being set as well as the crop */
1006- drv_data -> fmt .width = drv_data -> crop .width ;
1007- drv_data -> fmt .height = drv_data -> crop .height ;
1008- drv_data -> fmt .pitch = drv_data -> fmt .width
1009- * video_bits_per_pixel (drv_data -> fmt .pixelformat ) / BITS_PER_BYTE ;
1027+ /* save out the updated crop window registers */
1028+ ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG8 (GC2145_REG_RESET ),
1029+ GC2145_REG_RESET_P0_REGS );
1030+ if (ret < 0 ) {
1031+ return ret ;
1032+ }
1033+
1034+ ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_OUT_WIN_ROW_START , sel -> rect .top );
1035+ if (ret < 0 ) {
1036+ return ret ;
1037+ }
1038+ ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_OUT_WIN_COL_START , sel -> rect .left );
1039+ if (ret < 0 ) {
1040+ return ret ;
1041+ }
1042+ ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_OUT_WIN_HEIGHT , sel -> rect .height );
1043+ if (ret < 0 ) {
1044+ return ret ;
10101045 }
1011- return ret ;
1046+ ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_OUT_WIN_WIDTH , sel -> rect .width );
1047+ if (ret < 0 ) {
1048+ return ret ;
1049+ }
1050+
1051+
1052+ /* Only if valid do we update our crop rectangle */
1053+ drv_data -> crop = sel -> rect ;
1054+
1055+ /* enqueue/dequeue depend on this being set as well as the crop */
1056+ drv_data -> fmt .width = drv_data -> crop .width ;
1057+ drv_data -> fmt .height = drv_data -> crop .height ;
1058+ drv_data -> fmt .pitch = drv_data -> fmt .width *
1059+ video_bits_per_pixel (drv_data -> fmt .pixelformat ) / BITS_PER_BYTE ;
1060+
1061+ return 0 ;
10121062}
10131063
10141064
@@ -1137,7 +1187,7 @@ static int gc2145_set_fmt(const struct device *dev, struct video_format *fmt)
11371187 }
11381188
11391189 /* Set window size */
1140- ret = gc2145_set_resolution (dev , fmt -> width , fmt -> height , true );
1190+ ret = gc2145_gc2145_set_resolution (dev , fmt -> width , fmt -> height );
11411191
11421192 if (ret < 0 ) {
11431193 LOG_ERR ("Failed to set the resolution" );
@@ -1239,11 +1289,8 @@ static int gc2145_set_selection(const struct device *dev, struct video_selection
12391289 return - EINVAL ;
12401290 }
12411291
1242- struct gc2145_data * drv_data = dev -> data ;
1243-
12441292 if (sel -> target == VIDEO_SEL_TGT_CROP ) {
1245- drv_data -> crop = sel -> rect ;
1246- return gc2145_set_crop (dev );
1293+ return gc2145_set_crop (dev , sel );
12471294 }
12481295
12491296 return - EINVAL ;
@@ -1267,8 +1314,8 @@ static int gc2145_get_selection(const struct device *dev, struct video_selection
12671314 case VIDEO_SEL_TGT_NATIVE_SIZE :
12681315 sel -> rect .top = 0 ;
12691316 sel -> rect .left = 0 ;
1270- sel -> rect .width = UXGA_HSIZE / drv_data -> c_ratio ;
1271- sel -> rect .height = UXGA_VSIZE / drv_data -> r_ratio ;
1317+ sel -> rect .width = drv_data -> format_width ;
1318+ sel -> rect .height = drv_data -> format_height ;
12721319 break ;
12731320 default :
12741321 return - EINVAL ;
0 commit comments