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");
+
