@@ -706,10 +706,16 @@ static const struct video_reg8 default_regs[] = {
706
706
{0x46 , 0xcf },
707
707
708
708
{GC2145_REG_RESET , GC2145_REG_RESET_P0_REGS },
709
+ /* Hb and Vb from Teensy_camera */
709
710
{0x05 , 0x01 },
710
- {0x06 , 0x1C },
711
- {0x07 , 0x00 },
712
- {0x08 , 0x32 },
711
+ {0x06 , 0x3b },
712
+ {0x07 , 0x01 },
713
+ {0x08 , 0x0b },
714
+ /* Hb and Vb from current */
715
+ /*{0x05, 0x01}, */
716
+ /*{0x06, 0x1C}, */
717
+ /*{0x07, 0x00}, */
718
+ /*{0x08, 0x32}, */
713
719
{0x11 , 0x00 },
714
720
{0x12 , 0x1D },
715
721
{0x13 , 0x00 },
@@ -768,12 +774,23 @@ struct gc2145_ctrls {
768
774
struct gc2145_data {
769
775
struct gc2145_ctrls ctrls ;
770
776
struct video_format fmt ;
777
+ struct video_rect crop ;
778
+ uint16_t format_width ;
779
+ uint16_t format_height ;
780
+ uint8_t c_ratio ;
781
+ uint8_t r_ratio ;
771
782
};
772
783
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, \
784
+ #define GC2145_VIDEO_FORMAT_CAP (width , height , format ) \
785
+ { \
786
+ .pixelformat = format, .width_min = width, .width_max = width, \
787
+ .height_min = height, .height_max = height, .width_step = 0, .height_step = 0, \
788
+ }
789
+
790
+ #define GC2145_VIDEO_FORMAT_CAP_HL (width_l , width_h , height_l , height_h , format ) \
791
+ { \
792
+ .pixelformat = format, .width_min = width_l, .width_max = width_h, \
793
+ .height_min = height_l, .height_max = height_h, .width_step = 0, .height_step = 0,\
777
794
}
778
795
779
796
#define RESOLUTION_QVGA_W 320
@@ -792,6 +809,9 @@ static const struct video_format_cap fmts[] = {
792
809
GC2145_VIDEO_FORMAT_CAP (RESOLUTION_QVGA_W , RESOLUTION_QVGA_H , VIDEO_PIX_FMT_YUYV ),
793
810
GC2145_VIDEO_FORMAT_CAP (RESOLUTION_VGA_W , RESOLUTION_VGA_H , VIDEO_PIX_FMT_YUYV ),
794
811
GC2145_VIDEO_FORMAT_CAP (RESOLUTION_UXGA_W , RESOLUTION_UXGA_H , VIDEO_PIX_FMT_YUYV ),
812
+ /* Add catchall resolution */
813
+ GC2145_VIDEO_FORMAT_CAP_HL (128 , 1600 , 128 , 1200 , VIDEO_PIX_FMT_RGB565 ),
814
+ GC2145_VIDEO_FORMAT_CAP_HL (128 , 1600 , 128 , 1200 , VIDEO_PIX_FMT_YUYV ),
795
815
{0 },
796
816
};
797
817
@@ -843,47 +863,66 @@ static int gc2145_set_output_format(const struct device *dev, int output_format)
843
863
return 0 ;
844
864
}
845
865
846
- static int gc2145_set_resolution (const struct device * dev , uint32_t w , uint32_t h )
866
+
867
+ static int gc2145_gc2145_set_resolution (const struct device * dev , uint32_t w , uint32_t h )
847
868
{
848
869
const struct gc2145_config * cfg = dev -> config ;
870
+ struct gc2145_data * drv_data = dev -> data ;
849
871
int ret ;
850
872
851
873
uint16_t win_w ;
852
874
uint16_t win_h ;
853
- uint16_t c_ratio ;
854
- uint16_t r_ratio ;
855
875
uint16_t x ;
856
876
uint16_t y ;
857
877
uint16_t win_x ;
858
878
uint16_t win_y ;
859
879
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 );
880
+ if ((w == 0 ) || (h == 0 )) {
876
881
return - EIO ;
877
- };
882
+ }
883
+
884
+ /* If we are called from set_format, then we compute ratio and initialize crop */
885
+ drv_data -> c_ratio = RESOLUTION_UXGA_W / w ;
886
+ drv_data -> r_ratio = RESOLUTION_UXGA_H / h ;
887
+ if (drv_data -> c_ratio < drv_data -> r_ratio ) {
888
+ drv_data -> r_ratio = drv_data -> c_ratio ;
889
+ } else {
890
+ drv_data -> c_ratio = drv_data -> r_ratio ;
891
+ }
892
+
893
+ /* Restrict ratio to 3 for faster refresh ? */
894
+ if (drv_data -> c_ratio > 3 ) {
895
+ drv_data -> c_ratio = 3 ;
896
+ drv_data -> r_ratio = 3 ;
897
+ }
898
+
899
+ /* make sure we don't end up with ratio of 0 */
900
+ if (drv_data -> c_ratio == 0 ) {
901
+ return - EIO ;
902
+ }
903
+
904
+ /* remember the width and height passed in */
905
+ drv_data -> format_width = w ;
906
+ drv_data -> format_height = h ;
907
+
908
+ /* Default to crop rectangle being same size as passed in resolution */
909
+ drv_data -> crop .left = 0 ;
910
+ drv_data -> crop .top = 0 ;
911
+ drv_data -> crop .width = w ;
912
+ drv_data -> crop .height = h ;
913
+
878
914
879
915
/* 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 );
916
+
917
+ win_w = w * drv_data -> c_ratio ;
918
+ win_h = h * drv_data -> r_ratio ;
884
919
win_x = ((UXGA_HSIZE - win_w ) / 2 );
885
920
win_y = ((UXGA_VSIZE - win_h ) / 2 );
886
921
922
+
923
+ x = (((win_w / drv_data -> c_ratio ) - w ) / 2 );
924
+ y = (((win_h / drv_data -> r_ratio ) - h ) / 2 );
925
+
887
926
ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG8 (GC2145_REG_RESET ),
888
927
GC2145_REG_RESET_P0_REGS );
889
928
if (ret < 0 ) {
@@ -933,7 +972,8 @@ static int gc2145_set_resolution(const struct device *dev, uint32_t w, uint32_t
933
972
}
934
973
935
974
/* Set Sub-sampling ratio and mode */
936
- ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_SUBSAMPLE , ((r_ratio << 4 ) | c_ratio ));
975
+ ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_SUBSAMPLE ,
976
+ ((drv_data -> r_ratio << 4 ) | drv_data -> c_ratio ));
937
977
if (ret < 0 ) {
938
978
return ret ;
939
979
}
@@ -954,6 +994,66 @@ static int gc2145_set_resolution(const struct device *dev, uint32_t w, uint32_t
954
994
return 0 ;
955
995
}
956
996
997
+ static int gc2145_set_crop (const struct device * dev , struct video_selection * sel )
998
+ {
999
+ /* set the crop, start off with most of a duplicate of set resolution */
1000
+ int ret ;
1001
+ const struct gc2145_config * cfg = dev -> config ;
1002
+ struct gc2145_data * drv_data = dev -> data ;
1003
+
1004
+
1005
+ /* Verify the passed in rectangle is valid */
1006
+ if (((sel -> rect .left + sel -> rect .width ) > drv_data -> format_width ) ||
1007
+ ((sel -> rect .top + sel -> rect .height ) > drv_data -> format_height )) {
1008
+ LOG_INF ("(%u %u) %ux%u > %ux%u" , sel -> rect .left , sel -> rect .top ,
1009
+ sel -> rect .width , sel -> rect .height ,
1010
+ drv_data -> format_width , drv_data -> format_height );
1011
+ return - EINVAL ;
1012
+ }
1013
+
1014
+ /* if rectangle passed in is same as current, simply return */
1015
+ if (memcmp ((void * )& drv_data -> crop , (void * )& sel -> rect , sizeof (struct video_rect )) == 0 ) {
1016
+ return 0 ;
1017
+ }
1018
+
1019
+ /* save out the updated crop window registers */
1020
+ ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG8 (GC2145_REG_RESET ),
1021
+ GC2145_REG_RESET_P0_REGS );
1022
+ if (ret < 0 ) {
1023
+ return ret ;
1024
+ }
1025
+
1026
+ ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_OUT_WIN_ROW_START , sel -> rect .top );
1027
+ if (ret < 0 ) {
1028
+ return ret ;
1029
+ }
1030
+ ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_OUT_WIN_COL_START , sel -> rect .left );
1031
+ if (ret < 0 ) {
1032
+ return ret ;
1033
+ }
1034
+ ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_OUT_WIN_HEIGHT , sel -> rect .height );
1035
+ if (ret < 0 ) {
1036
+ return ret ;
1037
+ }
1038
+ ret = video_write_cci_reg (& cfg -> i2c , GC2145_REG_OUT_WIN_WIDTH , sel -> rect .width );
1039
+ if (ret < 0 ) {
1040
+ return ret ;
1041
+ }
1042
+
1043
+
1044
+ /* Only if valid do we update our crop rectangle */
1045
+ drv_data -> crop = sel -> rect ;
1046
+
1047
+ /* enqueue/dequeue depend on this being set as well as the crop */
1048
+ drv_data -> fmt .width = drv_data -> crop .width ;
1049
+ drv_data -> fmt .height = drv_data -> crop .height ;
1050
+ drv_data -> fmt .pitch = drv_data -> fmt .width *
1051
+ video_bits_per_pixel (drv_data -> fmt .pixelformat ) / BITS_PER_BYTE ;
1052
+
1053
+ return 0 ;
1054
+ }
1055
+
1056
+
957
1057
static int gc2145_check_connection (const struct device * dev )
958
1058
{
959
1059
const struct gc2145_config * cfg = dev -> config ;
@@ -1057,7 +1157,10 @@ static int gc2145_set_fmt(const struct device *dev, struct video_format *fmt)
1057
1157
1058
1158
/* Check if camera is capable of handling given format */
1059
1159
for (int i = 0 ; i < ARRAY_SIZE (fmts ) - 1 ; i ++ ) {
1060
- if (fmts [i ].width_min == fmt -> width && fmts [i ].height_min == fmt -> height &&
1160
+ if ((fmts [i ].width_min <= fmt -> width ) &&
1161
+ (fmts [i ].width_max >= fmt -> width ) &&
1162
+ (fmts [i ].height_min <= fmt -> height ) &&
1163
+ (fmts [i ].height_max >= fmt -> height ) &&
1061
1164
fmts [i ].pixelformat == fmt -> pixelformat ) {
1062
1165
res = i ;
1063
1166
break ;
@@ -1076,7 +1179,7 @@ static int gc2145_set_fmt(const struct device *dev, struct video_format *fmt)
1076
1179
}
1077
1180
1078
1181
/* Set window size */
1079
- ret = gc2145_set_resolution (dev , fmt -> width , fmt -> height );
1182
+ ret = gc2145_gc2145_set_resolution (dev , fmt -> width , fmt -> height );
1080
1183
1081
1184
if (ret < 0 ) {
1082
1185
LOG_ERR ("Failed to set the resolution" );
@@ -1171,12 +1274,57 @@ static int gc2145_set_ctrl(const struct device *dev, uint32_t id)
1171
1274
}
1172
1275
}
1173
1276
1277
+ static int gc2145_set_selection (const struct device * dev , struct video_selection * sel )
1278
+ {
1279
+ LOG_DBG ("called: (%p, %p: %u %u)" , dev , sel , sel -> type , sel -> target );
1280
+ if (sel -> type != VIDEO_BUF_TYPE_OUTPUT ) {
1281
+ return - EINVAL ;
1282
+ }
1283
+
1284
+ if (sel -> target == VIDEO_SEL_TGT_CROP ) {
1285
+ return gc2145_set_crop (dev , sel );
1286
+ }
1287
+
1288
+ return - EINVAL ;
1289
+ }
1290
+
1291
+ static int gc2145_get_selection (const struct device * dev , struct video_selection * sel )
1292
+ {
1293
+ LOG_DBG ("called: (%p, %p: %u %u)" , dev , sel , sel -> type , sel -> target );
1294
+ if (sel -> type != VIDEO_BUF_TYPE_OUTPUT ) {
1295
+ return - EINVAL ;
1296
+ }
1297
+
1298
+ struct gc2145_data * drv_data = dev -> data ;
1299
+
1300
+ switch (sel -> target ) {
1301
+ case VIDEO_SEL_TGT_COMPOSE :
1302
+ case VIDEO_SEL_TGT_CROP :
1303
+ sel -> rect = drv_data -> crop ;
1304
+ break ;
1305
+
1306
+ case VIDEO_SEL_TGT_NATIVE_SIZE :
1307
+ sel -> rect .top = 0 ;
1308
+ sel -> rect .left = 0 ;
1309
+ sel -> rect .width = drv_data -> format_width ;
1310
+ sel -> rect .height = drv_data -> format_height ;
1311
+ break ;
1312
+ default :
1313
+ return - EINVAL ;
1314
+ }
1315
+
1316
+ return 0 ;
1317
+ }
1318
+
1319
+
1174
1320
static DEVICE_API (video , gc2145_driver_api ) = {
1175
1321
.set_format = gc2145_set_fmt ,
1176
1322
.get_format = gc2145_get_fmt ,
1177
1323
.get_caps = gc2145_get_caps ,
1178
1324
.set_stream = gc2145_set_stream ,
1179
1325
.set_ctrl = gc2145_set_ctrl ,
1326
+ .set_selection = gc2145_set_selection ,
1327
+ .get_selection = gc2145_get_selection ,
1180
1328
};
1181
1329
1182
1330
static int gc2145_init_controls (const struct device * dev )
@@ -1214,8 +1362,8 @@ static int gc2145_init(const struct device *dev)
1214
1362
/* set default/init format VGA RGB565 */
1215
1363
struct video_format fmt = {
1216
1364
.pixelformat = VIDEO_PIX_FMT_RGB565 ,
1217
- .width = RESOLUTION_VGA_W ,
1218
- .height = RESOLUTION_VGA_H ,
1365
+ .width = RESOLUTION_QVGA_W ,
1366
+ .height = RESOLUTION_QVGA_H ,
1219
1367
};
1220
1368
int ret ;
1221
1369
const struct gc2145_config * cfg = dev -> config ;
0 commit comments