@@ -768,14 +768,23 @@ struct gc2145_ctrls {
768
768
struct gc2145_data {
769
769
struct gc2145_ctrls ctrls ;
770
770
struct video_format fmt ;
771
+ struct video_rect crop ;
772
+ uint16_t format_width ;
773
+ uint16_t format_height ;
774
+ uint8_t ratio ;
771
775
};
772
776
773
- #define GC2145_VIDEO_FORMAT_CAP (width , height , format ) \
774
- { \
775
- .pixelformat = format, .width_min = width, .width_max = width, \
776
- .height_min = height, .height_max = height, .width_step = 0, .height_step = 0, \
777
+ #define GC2145_VIDEO_FORMAT_CAP_HL (width_l , width_h , height_l , height_h , format , step_w , step_h ) \
778
+ { \
779
+ .pixelformat = (format), \
780
+ .width_min = (width_l), .width_max = (width_h), \
781
+ .height_min = (height_l), .height_max = (height_h), \
782
+ .width_step = (step_w), .height_step = (step_h), \
777
783
}
778
784
785
+ #define GC2145_VIDEO_FORMAT_CAP (width , height , format ) \
786
+ GC2145_VIDEO_FORMAT_CAP_HL((width), (width), (height), (height), (format), 0, 0)
787
+
779
788
#define RESOLUTION_QVGA_W 320
780
789
#define RESOLUTION_QVGA_H 240
781
790
@@ -785,13 +794,25 @@ struct gc2145_data {
785
794
#define RESOLUTION_UXGA_W 1600
786
795
#define RESOLUTION_UXGA_H 1200
787
796
797
+ #define RESOLUTION_MAX_W RESOLUTION_UXGA_W
798
+ #define RESOLUTION_MAX_H RESOLUTION_UXGA_H
799
+
800
+ /* Min not defined - smallest seen implementation is for QQVGA */
801
+ #define RESOLUTION_MIN_W 160
802
+ #define RESOLUTION_MIN_H 120
803
+
788
804
static const struct video_format_cap fmts [] = {
789
805
GC2145_VIDEO_FORMAT_CAP (RESOLUTION_QVGA_W , RESOLUTION_QVGA_H , VIDEO_PIX_FMT_RGB565 ),
790
806
GC2145_VIDEO_FORMAT_CAP (RESOLUTION_VGA_W , RESOLUTION_VGA_H , VIDEO_PIX_FMT_RGB565 ),
791
807
GC2145_VIDEO_FORMAT_CAP (RESOLUTION_UXGA_W , RESOLUTION_UXGA_H , VIDEO_PIX_FMT_RGB565 ),
792
808
GC2145_VIDEO_FORMAT_CAP (RESOLUTION_QVGA_W , RESOLUTION_QVGA_H , VIDEO_PIX_FMT_YUYV ),
793
809
GC2145_VIDEO_FORMAT_CAP (RESOLUTION_VGA_W , RESOLUTION_VGA_H , VIDEO_PIX_FMT_YUYV ),
794
810
GC2145_VIDEO_FORMAT_CAP (RESOLUTION_UXGA_W , RESOLUTION_UXGA_H , VIDEO_PIX_FMT_YUYV ),
811
+ /* Add catchall resolution */
812
+ GC2145_VIDEO_FORMAT_CAP_HL (RESOLUTION_MIN_W , RESOLUTION_MAX_W , RESOLUTION_MIN_H ,
813
+ RESOLUTION_MAX_H , VIDEO_PIX_FMT_RGB565 , 1 , 1 ),
814
+ GC2145_VIDEO_FORMAT_CAP_HL (RESOLUTION_MIN_W , RESOLUTION_MAX_W , RESOLUTION_MIN_H ,
815
+ RESOLUTION_MAX_H , VIDEO_PIX_FMT_YUYV , 1 , 1 ),
795
816
{0 },
796
817
};
797
818
@@ -843,44 +864,74 @@ static int gc2145_set_output_format(const struct device *dev, int output_format)
843
864
return 0 ;
844
865
}
845
866
867
+ static int gc2145_set_crop_registers (const struct gc2145_config * cfg , uint16_t x , uint16_t y ,
868
+ uint16_t w , uint16_t h )
869
+ {
870
+ int ret ;
871
+
872
+ ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_OUT_WIN_ROW_START , y );
873
+ if (ret < 0 ) {
874
+ return ret ;
875
+ }
876
+ ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_OUT_WIN_COL_START , x );
877
+ if (ret < 0 ) {
878
+ return ret ;
879
+ }
880
+ ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_OUT_WIN_HEIGHT , h );
881
+ if (ret < 0 ) {
882
+ return ret ;
883
+ }
884
+ ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_OUT_WIN_WIDTH , w );
885
+ if (ret < 0 ) {
886
+ return ret ;
887
+ }
888
+
889
+ /* Enable crop */
890
+ return video_write_cci_reg (& cfg -> i2c , GC2145_REG_CROP_ENABLE , GC2145_CROP_SET_ENABLE );
891
+ }
892
+
846
893
static int gc2145_set_resolution (const struct device * dev , uint32_t w , uint32_t h )
847
894
{
848
895
const struct gc2145_config * cfg = dev -> config ;
896
+ struct gc2145_data * drv_data = dev -> data ;
849
897
int ret ;
850
898
851
899
uint16_t win_w ;
852
900
uint16_t win_h ;
853
- uint16_t c_ratio ;
854
- uint16_t r_ratio ;
855
- uint16_t x ;
856
- uint16_t y ;
857
901
uint16_t win_x ;
858
902
uint16_t win_y ;
859
903
860
- /* Add the subsampling factor depending on resolution */
861
- switch (w ) {
862
- case RESOLUTION_QVGA_W :
863
- c_ratio = 3 ;
864
- r_ratio = 3 ;
865
- break ;
866
- case RESOLUTION_VGA_W :
867
- c_ratio = 2 ;
868
- r_ratio = 2 ;
869
- break ;
870
- case RESOLUTION_UXGA_W :
871
- c_ratio = 1 ;
872
- r_ratio = 1 ;
873
- break ;
874
- default :
875
- LOG_ERR ("Unsupported resolution %d %d" , w , h );
904
+ if ((w == 0 ) || (h == 0 )) {
876
905
return - EIO ;
877
- };
906
+ }
907
+
908
+ /* If we are called from set_format, then we compute ratio and initialize crop */
909
+ drv_data -> ratio = MIN (RESOLUTION_UXGA_W / w , RESOLUTION_UXGA_H / h );
910
+
911
+ /* make sure we don't end up with ratio of 0 */
912
+ if (drv_data -> ratio == 0 ) {
913
+ return - EIO ;
914
+ }
915
+
916
+ /* Restrict ratio to 3 for faster refresh ? */
917
+ if (drv_data -> ratio > 3 ) {
918
+ drv_data -> ratio = 3 ;
919
+ }
920
+
921
+ /* remember the width and height passed in */
922
+ drv_data -> format_width = w ;
923
+ drv_data -> format_height = h ;
924
+
925
+ /* Default to crop rectangle being same size as passed in resolution */
926
+ drv_data -> crop .left = 0 ;
927
+ drv_data -> crop .top = 0 ;
928
+ drv_data -> crop .width = w ;
929
+ drv_data -> crop .height = h ;
878
930
879
931
/* Calculates the window boundaries to obtain the desired resolution */
880
- win_w = w * c_ratio ;
881
- win_h = h * r_ratio ;
882
- x = (((win_w / c_ratio ) - w ) / 2 );
883
- y = (((win_h / r_ratio ) - h ) / 2 );
932
+
933
+ win_w = w * drv_data -> ratio ;
934
+ win_h = h * drv_data -> ratio ;
884
935
win_x = ((UXGA_HSIZE - win_w ) / 2 );
885
936
win_y = ((UXGA_VSIZE - win_h ) / 2 );
886
937
@@ -909,31 +960,14 @@ static int gc2145_set_resolution(const struct device *dev, uint32_t w, uint32_t
909
960
}
910
961
911
962
/* Set cropping window next. */
912
- ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_OUT_WIN_ROW_START , y );
913
- if (ret < 0 ) {
914
- return ret ;
915
- }
916
- ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_OUT_WIN_COL_START , x );
917
- if (ret < 0 ) {
918
- return ret ;
919
- }
920
- ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_OUT_WIN_HEIGHT , h );
921
- if (ret < 0 ) {
922
- return ret ;
923
- }
924
- ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_OUT_WIN_WIDTH , w );
925
- if (ret < 0 ) {
926
- return ret ;
927
- }
928
-
929
- /* Enable crop */
930
- ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_CROP_ENABLE , GC2145_CROP_SET_ENABLE );
963
+ ret = gc2145_set_crop_registers (cfg , 0 , 0 , w , h );
931
964
if (ret < 0 ) {
932
965
return ret ;
933
966
}
934
967
935
968
/* Set Sub-sampling ratio and mode */
936
- ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_SUBSAMPLE , ((r_ratio << 4 ) | c_ratio ));
969
+ ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_SUBSAMPLE ,
970
+ (drv_data -> ratio << 4 ) | drv_data -> ratio );
937
971
if (ret < 0 ) {
938
972
return ret ;
939
973
}
@@ -954,6 +988,52 @@ static int gc2145_set_resolution(const struct device *dev, uint32_t w, uint32_t
954
988
return 0 ;
955
989
}
956
990
991
+ static int gc2145_set_crop (const struct device * dev , struct video_selection * sel )
992
+ {
993
+ /* set the crop, start off with most of a duplicate of set resolution */
994
+ int ret ;
995
+ const struct gc2145_config * cfg = dev -> config ;
996
+ struct gc2145_data * drv_data = dev -> data ;
997
+
998
+ /* Verify the passed in rectangle is valid */
999
+ if (((sel -> rect .left + sel -> rect .width ) > drv_data -> format_width ) ||
1000
+ ((sel -> rect .top + sel -> rect .height ) > drv_data -> format_height )) {
1001
+ LOG_INF ("(%u %u) %ux%u > %ux%u" , sel -> rect .left , sel -> rect .top ,
1002
+ sel -> rect .width , sel -> rect .height ,
1003
+ drv_data -> format_width , drv_data -> format_height );
1004
+ return - EINVAL ;
1005
+ }
1006
+
1007
+ /* if rectangle passed in is same as current, simply return */
1008
+ if ((drv_data -> crop .left == sel -> rect .left ) && (drv_data -> crop .top == sel -> rect .top ) &&
1009
+ (drv_data -> crop .width == sel -> rect .width ) &&
1010
+ (drv_data -> crop .height == sel -> rect .height )) {
1011
+ return 0 ;
1012
+ }
1013
+
1014
+ /* save out the updated crop window registers */
1015
+ ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG8 (GC2145_REG_RESET ),
1016
+ GC2145_REG_RESET_P0_REGS );
1017
+ if (ret < 0 ) {
1018
+ return ret ;
1019
+ }
1020
+
1021
+ ret = gc2145_set_crop_registers (cfg , sel -> rect .left , sel -> rect .top ,
1022
+ sel -> rect .width , sel -> rect .height );
1023
+ if (ret < 0 ) {
1024
+ return ret ;
1025
+ }
1026
+
1027
+ /* Only if valid do we update our crop rectangle */
1028
+ drv_data -> crop = sel -> rect ;
1029
+
1030
+ /* enqueue/dequeue depend on this being set as well as the crop */
1031
+ drv_data -> fmt .width = drv_data -> crop .width ;
1032
+ drv_data -> fmt .height = drv_data -> crop .height ;
1033
+
1034
+ return 0 ;
1035
+ }
1036
+
957
1037
static int gc2145_check_connection (const struct device * dev )
958
1038
{
959
1039
const struct gc2145_config * cfg = dev -> config ;
@@ -1047,7 +1127,7 @@ static int gc2145_set_fmt(const struct device *dev, struct video_format *fmt)
1047
1127
{
1048
1128
struct gc2145_data * drv_data = dev -> data ;
1049
1129
const struct gc2145_config * cfg = dev -> config ;
1050
- size_t res = ARRAY_SIZE ( fmts ) ;
1130
+ size_t idx ;
1051
1131
int ret ;
1052
1132
1053
1133
if (memcmp (& drv_data -> fmt , fmt , sizeof (drv_data -> fmt )) == 0 ) {
@@ -1056,14 +1136,7 @@ static int gc2145_set_fmt(const struct device *dev, struct video_format *fmt)
1056
1136
}
1057
1137
1058
1138
/* Check if camera is capable of handling given format */
1059
- for (int i = 0 ; i < ARRAY_SIZE (fmts ) - 1 ; i ++ ) {
1060
- if (fmts [i ].width_min == fmt -> width && fmts [i ].height_min == fmt -> height &&
1061
- fmts [i ].pixelformat == fmt -> pixelformat ) {
1062
- res = i ;
1063
- break ;
1064
- }
1065
- }
1066
- if (res == ARRAY_SIZE (fmts )) {
1139
+ if (video_format_caps_index (fmts , fmt , & idx ) < 0 ) {
1067
1140
LOG_ERR ("Image format not supported" );
1068
1141
return - ENOTSUP ;
1069
1142
}
@@ -1171,12 +1244,55 @@ static int gc2145_set_ctrl(const struct device *dev, uint32_t id)
1171
1244
}
1172
1245
}
1173
1246
1247
+ static int gc2145_set_selection (const struct device * dev , struct video_selection * sel )
1248
+ {
1249
+ LOG_DBG ("called: (%u %u)" , sel -> type , sel -> target );
1250
+ if (sel -> type != VIDEO_BUF_TYPE_OUTPUT ) {
1251
+ return - EINVAL ;
1252
+ }
1253
+
1254
+ if (sel -> target != VIDEO_SEL_TGT_CROP ) {
1255
+ return - EINVAL ;
1256
+ }
1257
+
1258
+ return gc2145_set_crop (dev , sel );
1259
+ }
1260
+
1261
+ static int gc2145_get_selection (const struct device * dev , struct video_selection * sel )
1262
+ {
1263
+ LOG_DBG ("called: (%u %u)" , sel -> type , sel -> target );
1264
+ if (sel -> type != VIDEO_BUF_TYPE_OUTPUT ) {
1265
+ return - EINVAL ;
1266
+ }
1267
+
1268
+ struct gc2145_data * drv_data = dev -> data ;
1269
+
1270
+ switch (sel -> target ) {
1271
+ case VIDEO_SEL_TGT_CROP :
1272
+ sel -> rect = drv_data -> crop ;
1273
+ break ;
1274
+
1275
+ case VIDEO_SEL_TGT_NATIVE_SIZE :
1276
+ sel -> rect .top = 0 ;
1277
+ sel -> rect .left = 0 ;
1278
+ sel -> rect .width = drv_data -> format_width ;
1279
+ sel -> rect .height = drv_data -> format_height ;
1280
+ break ;
1281
+ default :
1282
+ return - EINVAL ;
1283
+ }
1284
+
1285
+ return 0 ;
1286
+ }
1287
+
1174
1288
static DEVICE_API (video , gc2145_driver_api ) = {
1175
1289
.set_format = gc2145_set_fmt ,
1176
1290
.get_format = gc2145_get_fmt ,
1177
1291
.get_caps = gc2145_get_caps ,
1178
1292
.set_stream = gc2145_set_stream ,
1179
1293
.set_ctrl = gc2145_set_ctrl ,
1294
+ .set_selection = gc2145_set_selection ,
1295
+ .get_selection = gc2145_get_selection ,
1180
1296
};
1181
1297
1182
1298
static int gc2145_init_controls (const struct device * dev )
0 commit comments