@@ -400,42 +400,57 @@ static u32 imx219_get_format_bpp(const struct v4l2_mbus_framefmt *format)
400400 }
401401}
402402
403- static void imx219_get_binning (struct v4l2_subdev_state * state , u8 * bin_h ,
404- u8 * bin_v )
403+ static unsigned int imx219_get_binning (struct v4l2_subdev_state * state ,
404+ u8 * bin_h , u8 * bin_v )
405405{
406406 const struct v4l2_mbus_framefmt * format =
407407 v4l2_subdev_state_get_format (state , 0 );
408- const struct v4l2_rect * crop = v4l2_subdev_state_get_crop (state , 0 );
409- u32 hbin = crop -> width / format -> width ;
410- u32 vbin = crop -> height / format -> height ;
408+ unsigned int bin_mode = IMX219_BINNING_NONE ;
409+ const struct imx219_mode * mode =
410+ v4l2_find_nearest_size (supported_modes ,
411+ ARRAY_SIZE (supported_modes ),
412+ width , height ,
413+ format -> width , format -> height );
414+ switch (format -> code ) {
415+ case MEDIA_BUS_FMT_SRGGB8_1X8 :
416+ case MEDIA_BUS_FMT_SGRBG8_1X8 :
417+ case MEDIA_BUS_FMT_SGBRG8_1X8 :
418+ case MEDIA_BUS_FMT_SBGGR8_1X8 :
419+ bin_mode = mode -> binning [BINNING_IDX_8_BIT ];
420+ break ;
421+
422+ case MEDIA_BUS_FMT_SRGGB10_1X10 :
423+ case MEDIA_BUS_FMT_SGRBG10_1X10 :
424+ case MEDIA_BUS_FMT_SGBRG10_1X10 :
425+ case MEDIA_BUS_FMT_SBGGR10_1X10 :
426+ bin_mode = mode -> binning [BINNING_IDX_10_BIT ];
427+ break ;
428+ }
411429
412430 * bin_h = IMX219_BINNING_NONE ;
413431 * bin_v = IMX219_BINNING_NONE ;
414432
415- /*
416- * Use analog binning only if both dimensions are binned, as it crops
417- * the other dimension.
418- */
419- if (hbin == 2 && vbin == 2 ) {
420- * bin_h = IMX219_BINNING_X2_ANALOG ;
421- * bin_v = IMX219_BINNING_X2_ANALOG ;
422-
423- return ;
424- }
425-
426- if (hbin == 2 )
427- * bin_h = IMX219_BINNING_X2 ;
428- if (vbin == 2 )
429- * bin_v = IMX219_BINNING_X2 ;
433+ if (* bin_h == 2 && * bin_v == 2 )
434+ return IMX219_BINNING_X2_ANALOG ;
435+ else if (* bin_h == 2 || * bin_v == 2 )
436+ /*
437+ * Don't use analog binning if only one dimension
438+ * is binned, as it crops the other dimension
439+ */
440+ return IMX219_BINNING_X2 ;
441+ else
442+ return IMX219_BINNING_NONE ;
430443}
431444
432445static inline u32 imx219_get_rate_factor (struct v4l2_subdev_state * state )
433446{
434447 u8 bin_h , bin_v ;
448+ unsigned int binning = imx219_get_binning (state , & bin_h , & bin_v );
435449
436- imx219_get_binning (state , & bin_h , & bin_v );
450+ if (binning == IMX219_BINNING_X2_ANALOG )
451+ return 2 ;
437452
438- return ( bin_h & bin_v ) == IMX219_BINNING_X2_ANALOG ? 2 : 1 ;
453+ return 1 ;
439454}
440455
441456/* -----------------------------------------------------------------------------
@@ -671,6 +686,7 @@ static int imx219_set_framefmt(struct imx219 *imx219,
671686{
672687 const struct v4l2_mbus_framefmt * format ;
673688 const struct v4l2_rect * crop ;
689+ unsigned int binning ;
674690 u8 bin_h , bin_v ;
675691 u32 bpp ;
676692 int ret = 0 ;
@@ -688,9 +704,11 @@ static int imx219_set_framefmt(struct imx219 *imx219,
688704 cci_write (imx219 -> regmap , IMX219_REG_Y_ADD_END_A ,
689705 crop -> top - IMX219_PIXEL_ARRAY_TOP + crop -> height - 1 , & ret );
690706
691- imx219_get_binning (state , & bin_h , & bin_v );
692- cci_write (imx219 -> regmap , IMX219_REG_BINNING_MODE_H , bin_h , & ret );
693- cci_write (imx219 -> regmap , IMX219_REG_BINNING_MODE_V , bin_v , & ret );
707+ binning = imx219_get_binning (state , & bin_h , & bin_v );
708+ cci_write (imx219 -> regmap , IMX219_REG_BINNING_MODE_H ,
709+ (bin_h == 2 ) ? binning : IMX219_BINNING_NONE , & ret );
710+ cci_write (imx219 -> regmap , IMX219_REG_BINNING_MODE_V ,
711+ (bin_v == 2 ) ? binning : IMX219_BINNING_NONE , & ret );
694712
695713 cci_write (imx219 -> regmap , IMX219_REG_X_OUTPUT_SIZE ,
696714 format -> width , & ret );
0 commit comments