Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 25 additions & 74 deletions drivers/media/i2c/imx219.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,6 @@
#define IMX219_PIXEL_ARRAY_WIDTH 3280U
#define IMX219_PIXEL_ARRAY_HEIGHT 2464U

enum binning_bit_depths {
BINNING_IDX_8_BIT,
BINNING_IDX_10_BIT,
BINNING_IDX_MAX
};

/* Mode : resolution and related config&values */
struct imx219_mode {
/* Frame width */
Expand All @@ -161,10 +155,6 @@ struct imx219_mode {

/* V-timing */
unsigned int fll_def;
unsigned int vts_def;

/* binning mode based on format code */
unsigned int binning[BINNING_IDX_MAX];
};

static const struct cci_reg_sequence imx219_common_regs[] = {
Expand Down Expand Up @@ -323,44 +313,24 @@ static const struct imx219_mode supported_modes[] = {
.width = 3280,
.height = 2464,
.fll_def = 3526,
.vts_def = 3526,
.binning = {
[BINNING_IDX_8_BIT] = IMX219_BINNING_NONE,
[BINNING_IDX_10_BIT] = IMX219_BINNING_NONE,
},
},
{
/* 1080P 30fps cropped */
.width = 1920,
.height = 1080,
.fll_def = 1763,
.vts_def = 1763,
.binning = {
[BINNING_IDX_8_BIT] = IMX219_BINNING_NONE,
[BINNING_IDX_10_BIT] = IMX219_BINNING_NONE,
},
},
{
/* 2x2 binned 60fps mode */
.width = 1640,
.height = 1232,
.fll_def = 1707,
.vts_def = 1763,
.binning = {
[BINNING_IDX_8_BIT] = IMX219_BINNING_X2_ANALOG,
[BINNING_IDX_10_BIT] = IMX219_BINNING_X2,
},
},
{
/* 640x480 60fps mode */
.width = 640,
.height = 480,
.fll_def = 1707,
.vts_def = 1763,
.binning = {
[BINNING_IDX_8_BIT] = IMX219_BINNING_X2_ANALOG,
[BINNING_IDX_10_BIT] = IMX219_BINNING_X2_ANALOG,
},
},
};

Expand Down Expand Up @@ -430,57 +400,42 @@ static u32 imx219_get_format_bpp(const struct v4l2_mbus_framefmt *format)
}
}

static unsigned int imx219_get_binning(struct v4l2_subdev_state *state,
u8 *bin_h, u8 *bin_v)
static void imx219_get_binning(struct v4l2_subdev_state *state, u8 *bin_h,
u8 *bin_v)
{
const struct v4l2_mbus_framefmt *format =
v4l2_subdev_state_get_format(state, 0);
unsigned int bin_mode = IMX219_BINNING_NONE;
const struct imx219_mode *mode =
v4l2_find_nearest_size(supported_modes,
ARRAY_SIZE(supported_modes),
width, height,
format->width, format->height);
switch (format->code) {
case MEDIA_BUS_FMT_SRGGB8_1X8:
case MEDIA_BUS_FMT_SGRBG8_1X8:
case MEDIA_BUS_FMT_SGBRG8_1X8:
case MEDIA_BUS_FMT_SBGGR8_1X8:
bin_mode = mode->binning[BINNING_IDX_8_BIT];
break;

case MEDIA_BUS_FMT_SRGGB10_1X10:
case MEDIA_BUS_FMT_SGRBG10_1X10:
case MEDIA_BUS_FMT_SGBRG10_1X10:
case MEDIA_BUS_FMT_SBGGR10_1X10:
bin_mode = mode->binning[BINNING_IDX_10_BIT];
break;
}
const struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0);
u32 hbin = crop->width / format->width;
u32 vbin = crop->height / format->height;

*bin_h = IMX219_BINNING_NONE;
*bin_v = IMX219_BINNING_NONE;

if (*bin_h == 2 && *bin_v == 2)
return bin_mode;
else if (*bin_h == 2 || *bin_v == 2)
/*
* Don't use analog binning if only one dimension
* is binned, as it crops the other dimension
*/
return IMX219_BINNING_X2;
else
return IMX219_BINNING_NONE;
/*
* Use analog binning only if both dimensions are binned, as it crops
* the other dimension.
*/
if (hbin == 2 && vbin == 2) {
*bin_h = IMX219_BINNING_X2_ANALOG;
*bin_v = IMX219_BINNING_X2_ANALOG;

return;
}

if (hbin == 2)
*bin_h = IMX219_BINNING_X2;
if (vbin == 2)
*bin_v = IMX219_BINNING_X2;
}

static inline u32 imx219_get_rate_factor(struct v4l2_subdev_state *state)
{
u8 bin_h, bin_v;
unsigned int binning = imx219_get_binning(state, &bin_h, &bin_v);

if (binning == IMX219_BINNING_X2_ANALOG)
return 2;
imx219_get_binning(state, &bin_h, &bin_v);

return 1;
return (bin_h & bin_v) == IMX219_BINNING_X2_ANALOG ? 2 : 1;
}

/* -----------------------------------------------------------------------------
Expand Down Expand Up @@ -716,7 +671,6 @@ static int imx219_set_framefmt(struct imx219 *imx219,
{
const struct v4l2_mbus_framefmt *format;
const struct v4l2_rect *crop;
unsigned int binning;
u8 bin_h, bin_v;
u32 bpp;
int ret = 0;
Expand All @@ -734,11 +688,9 @@ static int imx219_set_framefmt(struct imx219 *imx219,
cci_write(imx219->regmap, IMX219_REG_Y_ADD_END_A,
crop->top - IMX219_PIXEL_ARRAY_TOP + crop->height - 1, &ret);

binning = imx219_get_binning(state, &bin_h, &bin_v);
cci_write(imx219->regmap, IMX219_REG_BINNING_MODE_H,
(bin_h == 2) ? binning : IMX219_BINNING_NONE, &ret);
cci_write(imx219->regmap, IMX219_REG_BINNING_MODE_V,
(bin_v == 2) ? binning : IMX219_BINNING_NONE, &ret);
imx219_get_binning(state, &bin_h, &bin_v);
cci_write(imx219->regmap, IMX219_REG_BINNING_MODE_H, bin_h, &ret);
cci_write(imx219->regmap, IMX219_REG_BINNING_MODE_V, bin_v, &ret);

cci_write(imx219->regmap, IMX219_REG_X_OUTPUT_SIZE,
format->width, &ret);
Expand Down Expand Up @@ -924,7 +876,6 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
*/
bin_h = min(IMX219_PIXEL_ARRAY_WIDTH / format->width, 2U);
bin_v = min(IMX219_PIXEL_ARRAY_HEIGHT / format->height, 2U);
binning = min(bin_h, bin_v);

/* Ensure bin_h and bin_v are same to avoid 1:2 or 2:1 stretching */
binning = min(bin_h, bin_v);
Expand Down
Loading