148148#define IMX219_PIXEL_ARRAY_WIDTH 3280U
149149#define IMX219_PIXEL_ARRAY_HEIGHT 2464U
150150
151+ enum binning_mode {
152+ BINNING_NONE = IMX219_BINNING_NONE ,
153+ BINNING_X2 = IMX219_BINNING_X2 ,
154+ BINNING_ANALOG_X2 = IMX219_BINNING_X2_ANALOG ,
155+ };
156+
151157/* Mode : resolution and related config&values */
152158struct imx219_mode {
153159 /* Frame width */
@@ -324,13 +330,13 @@ static const struct imx219_mode supported_modes[] = {
324330 .vts_def = 1763 ,
325331 },
326332 {
327- /* 2x2 binned 30fps mode */
333+ /* 2x2 binned 60fps mode */
328334 .width = 1640 ,
329335 .height = 1232 ,
330336 .vts_def = 1763 ,
331337 },
332338 {
333- /* 640x480 30fps mode */
339+ /* 640x480 60fps mode */
334340 .width = 640 ,
335341 .height = 480 ,
336342 .vts_def = 1763 ,
@@ -385,6 +391,59 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
385391 return imx219_mbus_formats [i ];
386392}
387393
394+ static u32 imx219_get_format_bpp (const struct v4l2_mbus_framefmt * format )
395+ {
396+ switch (format -> code ) {
397+ case MEDIA_BUS_FMT_SRGGB8_1X8 :
398+ case MEDIA_BUS_FMT_SGRBG8_1X8 :
399+ case MEDIA_BUS_FMT_SGBRG8_1X8 :
400+ case MEDIA_BUS_FMT_SBGGR8_1X8 :
401+ return 8 ;
402+
403+ case MEDIA_BUS_FMT_SRGGB10_1X10 :
404+ case MEDIA_BUS_FMT_SGRBG10_1X10 :
405+ case MEDIA_BUS_FMT_SGBRG10_1X10 :
406+ case MEDIA_BUS_FMT_SBGGR10_1X10 :
407+ default :
408+ return 10 ;
409+ }
410+ }
411+
412+ static enum binning_mode imx219_get_binning (struct imx219 * imx219 , u8 * bin_h ,
413+ u8 * bin_v )
414+ {
415+ struct v4l2_subdev_state * state =
416+ v4l2_subdev_get_locked_active_state (& imx219 -> sd );
417+ const struct v4l2_mbus_framefmt * format =
418+ v4l2_subdev_state_get_format (state , 0 );
419+ const struct v4l2_rect * crop = v4l2_subdev_state_get_crop (state , 0 );
420+
421+ * bin_h = crop -> width / format -> width ;
422+ * bin_v = crop -> height / format -> height ;
423+
424+ if (* bin_h == 2 && * bin_v == 2 )
425+ return BINNING_ANALOG_X2 ;
426+ else if (* bin_h == 2 || * bin_v == 2 )
427+ /*
428+ * Don't use analog binning if only one dimension
429+ * is binned, as it crops the other dimension
430+ */
431+ return BINNING_X2 ;
432+ else
433+ return BINNING_NONE ;
434+ }
435+
436+ static inline u32 imx219_get_rate_factor (struct imx219 * imx219 )
437+ {
438+ u8 bin_h , bin_v ;
439+ enum binning_mode binning = imx219_get_binning (imx219 , & bin_h , & bin_v );
440+
441+ if (binning == BINNING_ANALOG_X2 )
442+ return 2 ;
443+
444+ return 1 ;
445+ }
446+
388447/* -----------------------------------------------------------------------------
389448 * Controls
390449 */
@@ -396,10 +455,12 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
396455 struct i2c_client * client = v4l2_get_subdevdata (& imx219 -> sd );
397456 const struct v4l2_mbus_framefmt * format ;
398457 struct v4l2_subdev_state * state ;
458+ u32 rate_factor ;
399459 int ret = 0 ;
400460
401461 state = v4l2_subdev_get_locked_active_state (& imx219 -> sd );
402462 format = v4l2_subdev_state_get_format (state , 0 );
463+ rate_factor = imx219_get_rate_factor (imx219 );
403464
404465 if (ctrl -> id == V4L2_CID_VBLANK ) {
405466 int exposure_max , exposure_def ;
@@ -428,7 +489,7 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
428489 break ;
429490 case V4L2_CID_EXPOSURE :
430491 cci_write (imx219 -> regmap , IMX219_REG_EXPOSURE ,
431- ctrl -> val , & ret );
492+ ctrl -> val / rate_factor , & ret );
432493 break ;
433494 case V4L2_CID_DIGITAL_GAIN :
434495 cci_write (imx219 -> regmap , IMX219_REG_DIGITAL_GAIN ,
@@ -445,7 +506,7 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
445506 break ;
446507 case V4L2_CID_VBLANK :
447508 cci_write (imx219 -> regmap , IMX219_REG_VTS ,
448- format -> height + ctrl -> val , & ret );
509+ ( format -> height + ctrl -> val ) / rate_factor , & ret );
449510 break ;
450511 case V4L2_CID_TEST_PATTERN_RED :
451512 cci_write (imx219 -> regmap , IMX219_REG_TESTP_RED ,
@@ -613,29 +674,14 @@ static int imx219_set_framefmt(struct imx219 *imx219,
613674{
614675 const struct v4l2_mbus_framefmt * format ;
615676 const struct v4l2_rect * crop ;
616- unsigned int bpp ;
617- u64 bin_h , bin_v ;
677+ enum binning_mode binning ;
678+ u8 bin_h , bin_v ;
679+ u32 bpp ;
618680 int ret = 0 ;
619681
620682 format = v4l2_subdev_state_get_format (state , 0 );
621683 crop = v4l2_subdev_state_get_crop (state , 0 );
622-
623- switch (format -> code ) {
624- case MEDIA_BUS_FMT_SRGGB8_1X8 :
625- case MEDIA_BUS_FMT_SGRBG8_1X8 :
626- case MEDIA_BUS_FMT_SGBRG8_1X8 :
627- case MEDIA_BUS_FMT_SBGGR8_1X8 :
628- bpp = 8 ;
629- break ;
630-
631- case MEDIA_BUS_FMT_SRGGB10_1X10 :
632- case MEDIA_BUS_FMT_SGRBG10_1X10 :
633- case MEDIA_BUS_FMT_SGBRG10_1X10 :
634- case MEDIA_BUS_FMT_SBGGR10_1X10 :
635- default :
636- bpp = 10 ;
637- break ;
638- }
684+ bpp = imx219_get_format_bpp (format );
639685
640686 cci_write (imx219 -> regmap , IMX219_REG_X_ADD_STA_A ,
641687 crop -> left - IMX219_PIXEL_ARRAY_LEFT , & ret );
@@ -646,28 +692,11 @@ static int imx219_set_framefmt(struct imx219 *imx219,
646692 cci_write (imx219 -> regmap , IMX219_REG_Y_ADD_END_A ,
647693 crop -> top - IMX219_PIXEL_ARRAY_TOP + crop -> height - 1 , & ret );
648694
649- switch (crop -> width / format -> width ) {
650- case 1 :
651- default :
652- bin_h = IMX219_BINNING_NONE ;
653- break ;
654- case 2 :
655- bin_h = bpp == 8 ? IMX219_BINNING_X2_ANALOG : IMX219_BINNING_X2 ;
656- break ;
657- }
658-
659- switch (crop -> height / format -> height ) {
660- case 1 :
661- default :
662- bin_v = IMX219_BINNING_NONE ;
663- break ;
664- case 2 :
665- bin_v = bpp == 8 ? IMX219_BINNING_X2_ANALOG : IMX219_BINNING_X2 ;
666- break ;
667- }
668-
669- cci_write (imx219 -> regmap , IMX219_REG_BINNING_MODE_H , bin_h , & ret );
670- cci_write (imx219 -> regmap , IMX219_REG_BINNING_MODE_V , bin_v , & ret );
695+ binning = imx219_get_binning (imx219 , & bin_h , & bin_v );
696+ cci_write (imx219 -> regmap , IMX219_REG_BINNING_MODE_H ,
697+ (bin_h == 2 ) ? binning : BINNING_NONE , & ret );
698+ cci_write (imx219 -> regmap , IMX219_REG_BINNING_MODE_V ,
699+ (bin_v == 2 ) ? binning : BINNING_NONE , & ret );
671700
672701 cci_write (imx219 -> regmap , IMX219_REG_X_OUTPUT_SIZE ,
673702 format -> width , & ret );
@@ -873,6 +902,7 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
873902 int exposure_max ;
874903 int exposure_def ;
875904 int hblank ;
905+ int pixel_rate ;
876906
877907 /* Update limits and set FPS to default */
878908 __v4l2_ctrl_modify_range (imx219 -> vblank , IMX219_VBLANK_MIN ,
@@ -896,6 +926,12 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
896926 hblank = IMX219_PPL_DEFAULT - mode -> width ;
897927 __v4l2_ctrl_modify_range (imx219 -> hblank , hblank , hblank , 1 ,
898928 hblank );
929+
930+ /* Scale the pixel rate based on the mode specific factor */
931+ pixel_rate = imx219_get_pixel_rate (imx219 ) *
932+ imx219_get_rate_factor (imx219 );
933+ __v4l2_ctrl_modify_range (imx219 -> pixel_rate , pixel_rate ,
934+ pixel_rate , 1 , pixel_rate );
899935 }
900936
901937 return 0 ;
0 commit comments