210 lines
7.3 KiB
Diff
210 lines
7.3 KiB
Diff
diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
|
|
index a05d5e9f..7d453abd 100644
|
|
--- a/drivers/media/i2c/imx219.c
|
|
+++ b/drivers/media/i2c/imx219.c
|
|
@@ -56,6 +56,8 @@ struct imx219_mode {
|
|
u32 hts_def;
|
|
u32 vts_def;
|
|
const struct imx219_reg *reg_list;
|
|
+ u8 binning_v; // 0 = no binning, 1 = 2x binning, 2 = 4x binning
|
|
+ u8 binning_h;
|
|
};
|
|
|
|
/* MCLK:24MHz 3280x2464 21.2fps MIPI LANE2 */
|
|
@@ -70,8 +72,6 @@ static const struct imx219_reg imx219_init_tab_3280_2464_21fps[] = {
|
|
{0x0128, 0x00}, /* DPHY_CNTRL */
|
|
{0x012A, 0x18}, /* EXCK_FREQ[15:8] */
|
|
{0x012B, 0x00}, /* EXCK_FREQ[7:0] */
|
|
- {0x015A, 0x01}, /* INTEG TIME[15:8] */
|
|
- {0x015B, 0xF4}, /* INTEG TIME[7:0] */
|
|
{0x0160, 0x09}, /* FRM_LENGTH_A[15:8] */
|
|
{0x0161, 0xC4}, /* FRM_LENGTH_A[7:0] */
|
|
{0x0162, 0x0D}, /* LINE_LENGTH_A[15:8] */
|
|
@@ -163,6 +163,56 @@ static const struct imx219_reg imx219_init_tab_1920_1080_30fps[] = {
|
|
{IMX219_TABLE_END, 0x00}
|
|
};
|
|
|
|
+/* MCLK:24MHz 1640x1232 2x2 binning 30fps MIPI LANE2 */
|
|
+static const struct imx219_reg imx219_init_tab_1640_1232_30fps[] = {
|
|
+ {0x30EB, 0x05}, /* Access Code for address over 0x3000 */
|
|
+ {0x30EB, 0x0C}, /* Access Code for address over 0x3000 */
|
|
+ {0x300A, 0xFF}, /* Access Code for address over 0x3000 */
|
|
+ {0x300B, 0xFF}, /* Access Code for address over 0x3000 */
|
|
+ {0x30EB, 0x05}, /* Access Code for address over 0x3000 */
|
|
+ {0x30EB, 0x09}, /* Access Code for address over 0x3000 */
|
|
+ {0x0114, 0x01}, /* CSI_LANE_MODE[1:0} */
|
|
+ {0x0128, 0x00}, /* DPHY_CNTRL */
|
|
+ {0x012A, 0x18}, /* EXCK_FREQ[15:8] */
|
|
+ {0x012B, 0x00}, /* EXCK_FREQ[7:0] */
|
|
+ {0x0160, 0x06}, /* FRM_LENGTH_A[15:8] */
|
|
+ {0x0161, 0xE6}, /* FRM_LENGTH_A[7:0] */
|
|
+ {0x0162, 0x0D}, /* LINE_LENGTH_A[15:8] */
|
|
+ {0x0163, 0x78}, /* LINE_LENGTH_A[7:0] */
|
|
+ {0x0260, 0x06}, /* FRM_LENGTH_B[15:8] */
|
|
+ {0x0261, 0xE6}, /* FRM_LENGTH_B[7:0] */
|
|
+ {0x0262, 0x0D}, /* LINE_LENGTH_B[15:8] */
|
|
+ {0x0263, 0x78}, /* LINE_LENGTH_B[7:0] */
|
|
+ {0x0170, 0x01}, /* X_ODD_INC_A[2:0] */
|
|
+ {0x0171, 0x01}, /* Y_ODD_INC_A[2:0] */
|
|
+ {0x0270, 0x01}, /* X_ODD_INC_B[2:0] */
|
|
+ {0x0271, 0x01}, /* Y_ODD_INC_B[2:0] */
|
|
+ {0x0174, 0x01}, /* BINNING_MODE_H_A */
|
|
+ {0x0175, 0x01}, /* BINNING_MODE_V_A */
|
|
+ {0x0274, 0x01}, /* BINNING_MODE_H_B */
|
|
+ {0x0275, 0x01}, /* BINNING_MODE_V_B */
|
|
+ {0x018C, 0x0A}, /* CSI_DATA_FORMAT_A[15:8] */
|
|
+ {0x018D, 0x0A}, /* CSI_DATA_FORMAT_A[7:0] */
|
|
+ {0x028C, 0x0A}, /* CSI_DATA_FORMAT_B[15:8] */
|
|
+ {0x028D, 0x0A}, /* CSI_DATA_FORMAT_B[7:0] */
|
|
+ {0x0301, 0x05}, /* VTPXCK_DIV */
|
|
+ {0x0303, 0x01}, /* VTSYCK_DIV */
|
|
+ {0x0304, 0x03}, /* PREPLLCK_VT_DIV[3:0] */
|
|
+ {0x0305, 0x03}, /* PREPLLCK_OP_DIV[3:0] */
|
|
+ {0x0306, 0x00}, /* PLL_VT_MPY[10:8] */
|
|
+ {0x0307, 0x39}, /* PLL_VT_MPY[7:0] */
|
|
+ {0x0309, 0x0A}, /* OPPXCK_DIV[4:0] */
|
|
+ {0x030B, 0x01}, /* OPSYCK_DIV */
|
|
+ {0x030C, 0x00}, /* PLL_OP_MPY[10:8] */
|
|
+ {0x030D, 0x72}, /* PLL_OP_MPY[7:0] */
|
|
+ {0x455E, 0x00}, /* CIS Tuning */
|
|
+ {0x471E, 0x4B}, /* CIS Tuning */
|
|
+ {0x4767, 0x0F}, /* CIS Tuning */
|
|
+ {0x4750, 0x14}, /* CIS Tuning */
|
|
+ {0x47B4, 0x14}, /* CIS Tuning */
|
|
+ {IMX219_TABLE_END, 0x00}
|
|
+};
|
|
+
|
|
static const struct imx219_reg start[] = {
|
|
{0x0100, 0x01}, /* mode select streaming on */
|
|
{IMX219_TABLE_END, 0x00}
|
|
@@ -241,6 +291,8 @@ static const struct imx219_mode supported_modes[] = {
|
|
.hts_def = 0x0d78 - IMX219_EXP_LINES_MARGIN,
|
|
.vts_def = 0x06E6,
|
|
.reg_list = imx219_init_tab_1920_1080_30fps,
|
|
+ .binning_h = 0,
|
|
+ .binning_v = 0,
|
|
},
|
|
{
|
|
.width = 3280,
|
|
@@ -249,6 +301,18 @@ static const struct imx219_mode supported_modes[] = {
|
|
.hts_def = 0x0d78 - IMX219_EXP_LINES_MARGIN,
|
|
.vts_def = 0x09c4,
|
|
.reg_list = imx219_init_tab_3280_2464_21fps,
|
|
+ .binning_h = 0,
|
|
+ .binning_v = 0,
|
|
+ },
|
|
+ {
|
|
+ .width = 1640,
|
|
+ .height = 1232,
|
|
+ .max_fps = 30,
|
|
+ .hts_def = 0x0d78 - IMX219_EXP_LINES_MARGIN,
|
|
+ .vts_def = 0x06E6,
|
|
+ .reg_list = imx219_init_tab_1640_1232_30fps,
|
|
+ .binning_h = 1,
|
|
+ .binning_v = 1,
|
|
},
|
|
};
|
|
|
|
@@ -328,8 +392,11 @@ static int imx219_s_stream(struct v4l2_subdev *sd, int enable)
|
|
u8 reg = 0x00;
|
|
int ret;
|
|
|
|
- if (!enable)
|
|
- return reg_write_table(client, stop);
|
|
+ if (!enable) {
|
|
+ ret = reg_write_table(client, stop);
|
|
+ mdelay(100);
|
|
+ return ret;
|
|
+ }
|
|
|
|
ret = reg_write_table(client, priv->cur_mode->reg_list);
|
|
if (ret)
|
|
@@ -399,6 +466,15 @@ static int imx219_s_stream(struct v4l2_subdev *sd, int enable)
|
|
if (ret)
|
|
return ret;
|
|
|
|
+ /* Set exposure and gain */
|
|
+ ret = reg_write(client, 0x0157, priv->analogue_gain);
|
|
+ ret |= reg_write(client, 0x0158, priv->digital_gain >> 8);
|
|
+ ret |= reg_write(client, 0x0159, priv->digital_gain & 0xff);
|
|
+ ret |= reg_write(client, 0x015a, priv->exposure_time >> 8);
|
|
+ ret |= reg_write(client, 0x015b, priv->exposure_time & 0xff);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
return reg_write_table(client, start);
|
|
}
|
|
|
|
@@ -566,12 +642,11 @@ static int imx219_s_ctrl(struct v4l2_ctrl *ctrl)
|
|
ret = reg_write(client, 0x0157, priv->analogue_gain);
|
|
ret |= reg_write(client, 0x0158, priv->digital_gain >> 8);
|
|
ret |= reg_write(client, 0x0159, priv->digital_gain & 0xff);
|
|
-
|
|
+
|
|
return ret;
|
|
|
|
case V4L2_CID_EXPOSURE:
|
|
priv->exposure_time = ctrl->val;
|
|
-
|
|
ret = reg_write(client, 0x015a, priv->exposure_time >> 8);
|
|
ret |= reg_write(client, 0x015b, priv->exposure_time & 0xff);
|
|
return ret;
|
|
@@ -650,7 +725,14 @@ static int imx219_set_fmt(struct v4l2_subdev *sd,
|
|
return 0;
|
|
|
|
mode = imx219_find_best_fit(fmt);
|
|
- fmt->format.code = MEDIA_BUS_FMT_SRGGB10_1X10;
|
|
+ if(priv->hflip == 0 && priv->vflip == 0)
|
|
+ fmt->format.code = MEDIA_BUS_FMT_SRGGB10_1X10;
|
|
+ else if(priv->hflip != 0 && priv->vflip == 0)
|
|
+ fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
|
|
+ else if(priv->hflip == 0 && priv->vflip != 0)
|
|
+ fmt->format.code = MEDIA_BUS_FMT_SGBRG10_1X10;
|
|
+ else
|
|
+ fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
|
|
fmt->format.width = mode->width;
|
|
fmt->format.height = mode->height;
|
|
fmt->format.field = V4L2_FIELD_NONE;
|
|
@@ -667,14 +749,14 @@ static int imx219_set_fmt(struct v4l2_subdev *sd,
|
|
pixel_rate, 1, pixel_rate);
|
|
|
|
/* reset crop window */
|
|
- priv->crop_rect.left = 1640 - (mode->width / 2);
|
|
+ priv->crop_rect.left = 1640 - ((mode->width << mode->binning_h) / 2);
|
|
if (priv->crop_rect.left < 0)
|
|
priv->crop_rect.left = 0;
|
|
- priv->crop_rect.top = 1232 - (mode->height / 2);
|
|
+ priv->crop_rect.top = 1232 - ((mode->height << mode->binning_v) / 2);
|
|
if (priv->crop_rect.top < 0)
|
|
priv->crop_rect.top = 0;
|
|
- priv->crop_rect.width = mode->width;
|
|
- priv->crop_rect.height = mode->height;
|
|
+ priv->crop_rect.width = (mode->width << mode->binning_h);
|
|
+ priv->crop_rect.height = (mode->height << mode->binning_v);
|
|
|
|
return 0;
|
|
}
|
|
@@ -692,7 +774,16 @@ static int imx219_get_fmt(struct v4l2_subdev *sd,
|
|
|
|
fmt->format.width = mode->width;
|
|
fmt->format.height = mode->height;
|
|
- fmt->format.code = MEDIA_BUS_FMT_SRGGB10_1X10;
|
|
+
|
|
+ if(priv->hflip == 0 && priv->vflip == 0)
|
|
+ fmt->format.code = MEDIA_BUS_FMT_SRGGB10_1X10;
|
|
+ else if(priv->hflip != 0 && priv->vflip == 0)
|
|
+ fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
|
|
+ else if(priv->hflip == 0 && priv->vflip != 0)
|
|
+ fmt->format.code = MEDIA_BUS_FMT_SGBRG10_1X10;
|
|
+ else
|
|
+ fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
|
|
+
|
|
fmt->format.field = V4L2_FIELD_NONE;
|
|
|
|
return 0;
|
|
@@ -960,3 +1051,4 @@ module_i2c_driver(imx219_i2c_driver);
|
|
MODULE_DESCRIPTION("Sony IMX219 Camera driver");
|
|
MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
|
|
MODULE_LICENSE("GPL v2");
|
|
+
|