msm: camera: Add support for low power configuration in camera

Camera may run in a low power background mode. Configure the sensor
to run at lowest clock and vfe to request minimum bandwidth.

Change-Id: Idf6e5fb069c5a3cdbbbddb760614fee4510d81dc
Signed-off-by: Nishant Pandit <npandit@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index bc1eded..3955e77 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -356,6 +356,26 @@
 	},
 };
 
+static struct msm_bus_vectors cam_low_power_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 1451520,
+		.ib  = 3870720,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
 
 static struct msm_bus_paths cam_bus_client_config[] = {
 	{
@@ -386,6 +406,10 @@
 		ARRAY_SIZE(cam_dual_vectors),
 		cam_dual_vectors,
 	},
+	{
+		ARRAY_SIZE(cam_low_power_vectors),
+		cam_low_power_vectors,
+	},
 };
 
 static struct msm_bus_scale_pdata cam_bus_client_pdata = {
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 9f70ac2..ae496f9 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -634,6 +634,7 @@
 	S_DEFAULT,
 	S_LIVESHOT,
 	S_DUAL,
+	S_LOW_POWER,
 	S_EXIT
 };
 
diff --git a/drivers/media/video/msm/io/msm_io_8960.c b/drivers/media/video/msm/io/msm_io_8960.c
index 808cc32..ab3ea5d 100644
--- a/drivers/media/video/msm/io/msm_io_8960.c
+++ b/drivers/media/video/msm/io/msm_io_8960.c
@@ -103,6 +103,14 @@
 		} else
 			CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
 		break;
+	case S_LOW_POWER:
+		if (bus_perf_client) {
+			rc = msm_bus_scale_client_update_request(
+				bus_perf_client, 7);
+			CDBG("%s: S_LOW_POWER rc = %d\n", __func__, rc);
+		} else
+			CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
+		break;
 	case S_DEFAULT:
 		break;
 	default:
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 3c8563b..3d14de5 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -533,6 +533,17 @@
 		}
 		break;
 
+	case MSM_CAM_IOCTL_AXI_LOW_POWER_MODE:
+		if (p_mctl->axi_sdev) {
+			v4l2_set_subdev_hostdata(p_mctl->axi_sdev, p_mctl);
+			rc = v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
+				VIDIOC_MSM_AXI_LOW_POWER_MODE,
+				(void __user *)arg);
+		} else {
+			rc = 0;
+		}
+		break;
+
 	default:
 		/* ISP config*/
 		D("%s:%d: go to default. Calling msm_isp_config\n",
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 999783e..ddadf0b 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -102,11 +102,12 @@
 
 int32_t msm_sensor_write_init_settings(struct msm_sensor_ctrl_t *s_ctrl)
 {
-	int32_t rc;
-	rc = msm_sensor_write_all_conf_array(
-		s_ctrl->sensor_i2c_client,
-		s_ctrl->msm_sensor_reg->init_settings,
-		s_ctrl->msm_sensor_reg->init_size);
+	int32_t rc = 0;
+	if (s_ctrl->msm_sensor_reg->init_settings)
+		rc = msm_sensor_write_all_conf_array(
+			s_ctrl->sensor_i2c_client,
+			s_ctrl->msm_sensor_reg->init_settings,
+			s_ctrl->msm_sensor_reg->init_size);
 	return rc;
 }
 
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.c b/drivers/media/video/msm/vfe/msm_vfe32.c
index 281349f..1788779 100755
--- a/drivers/media/video/msm/vfe/msm_vfe32.c
+++ b/drivers/media/video/msm/vfe/msm_vfe32.c
@@ -5758,6 +5758,7 @@
 	if (axi_ctrl->share_ctrl->axi_ref_cnt > 1)
 		return rc;
 	axi_ctrl->share_ctrl->dual_enabled = dual_enabled;
+	axi_ctrl->share_ctrl->lp_mode = 0;
 	spin_lock_init(&axi_ctrl->tasklet_lock);
 	INIT_LIST_HEAD(&axi_ctrl->tasklet_q);
 	spin_lock_init(&axi_ctrl->share_ctrl->sd_notify_lock);
@@ -5916,6 +5917,23 @@
 		vfe32_ctrl->share_ctrl->vfebase);
 }
 
+int msm_axi_set_low_power_mode(struct v4l2_subdev *sd, void *arg)
+{
+	uint8_t lp_mode = 0;
+	int rc = 0;
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	if (copy_from_user(&lp_mode,
+		(void __user *)(arg),
+		sizeof(uint8_t))) {
+		rc = -EFAULT;
+		return rc;
+	}
+	axi_ctrl->share_ctrl->lp_mode = lp_mode;
+	if (lp_mode)
+		axi_ctrl->share_ctrl->dual_enabled = 0;
+	return rc;
+}
+
 void axi_abort(struct axi_ctrl_t *axi_ctrl)
 {
 	uint8_t  axi_busy_flag = true;
@@ -6144,9 +6162,14 @@
 
 	switch (vfe_params.cmd_type) {
 	case AXI_CMD_PREVIEW:
-		if (!axi_ctrl->share_ctrl->dual_enabled)
+		if (axi_ctrl->share_ctrl->lp_mode)
 			msm_camio_bus_scale_cfg(
-			pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+				pmctl->sdata->pdata->cam_bus_scale_table,
+				S_LOW_POWER);
+		else if (!axi_ctrl->share_ctrl->dual_enabled)
+			msm_camio_bus_scale_cfg(
+				pmctl->sdata->pdata->cam_bus_scale_table,
+				S_PREVIEW);
 		break;
 	case AXI_CMD_CAPTURE:
 	case AXI_CMD_RAW_CAPTURE:
@@ -6160,9 +6183,14 @@
 			pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
 		return;
 	case AXI_CMD_ZSL:
-		if (!axi_ctrl->share_ctrl->dual_enabled)
+		if (axi_ctrl->share_ctrl->lp_mode)
 			msm_camio_bus_scale_cfg(
-			pmctl->sdata->pdata->cam_bus_scale_table, S_ZSL);
+				pmctl->sdata->pdata->cam_bus_scale_table,
+				S_LOW_POWER);
+		else if (!axi_ctrl->share_ctrl->dual_enabled)
+			msm_camio_bus_scale_cfg(
+				pmctl->sdata->pdata->cam_bus_scale_table,
+				S_ZSL);
 		break;
 	case AXI_CMD_LIVESHOT:
 		if (!axi_ctrl->share_ctrl->dual_enabled)
@@ -6978,6 +7006,9 @@
 		rc = msm_axi_subdev_init(sd, dual_enabled);
 		}
 		break;
+	case VIDIOC_MSM_AXI_LOW_POWER_MODE:
+		rc = msm_axi_set_low_power_mode(sd, arg);
+		break;
 	case VIDIOC_MSM_AXI_CFG:
 		rc = msm_axi_config(sd, arg);
 		break;
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.h b/drivers/media/video/msm/vfe/msm_vfe32.h
index 1c1f441..0eae60cf 100644
--- a/drivers/media/video/msm/vfe/msm_vfe32.h
+++ b/drivers/media/video/msm/vfe/msm_vfe32.h
@@ -978,6 +978,7 @@
 	uint16_t cmd_type;
 	uint8_t vfe_reset_flag;
 	uint8_t dual_enabled;
+	uint8_t lp_mode;
 
 	uint8_t axi_ref_cnt;
 	uint16_t comp_output_mode;
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 18b641f..7241e90 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -243,8 +243,11 @@
 #define MSM_CAM_IOCTL_V4L2_EVT_NATIVE_FRONT_CMD \
 	_IOWR(MSM_CAM_IOCTL_MAGIC, 69, struct msm_camera_v4l2_ioctl_t)
 
+#define MSM_CAM_IOCTL_AXI_LOW_POWER_MODE \
+	_IOWR(MSM_CAM_IOCTL_MAGIC, 70, uint8_t *)
+
 #define MSM_CAM_IOCTL_INTF_MCTL_MAPPING_CFG \
-	_IOR(MSM_CAM_IOCTL_MAGIC, 70, struct intf_mctl_mapping_cfg *)
+	_IOR(MSM_CAM_IOCTL_MAGIC, 71, struct intf_mctl_mapping_cfg *)
 
 struct ioctl_native_cmd {
 	unsigned short mode;
@@ -2063,6 +2066,10 @@
 #define VIDIOC_MSM_VFE_RELEASE \
 	_IO('V', BASE_VIDIOC_PRIVATE + 25)
 
+#define VIDIOC_MSM_AXI_LOW_POWER_MODE \
+	_IO('V', BASE_VIDIOC_PRIVATE + 26)
+
+
 struct msm_camera_v4l2_ioctl_t {
 	uint32_t id;
 	uint32_t len;