瀏覽代碼

Merge changes I6682d41e,Ifc57987a into camera-kernel.lnx.6.0

* changes:
  Snap for drop 05/23/2022 mainline 776 LA.VENDOR.13.2.0.AU221
  msm: camera: common: Add support for variable fps feature
Wasim Khan 3 年之前
父節點
當前提交
e66155bc96

+ 59 - 23
drivers/cam_isp/cam_isp_context.c

@@ -2299,7 +2299,7 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state(
 	return rc;
 }
 
-static int __cam_isp_ctx_apply_req_offline(
+static int __cam_isp_ctx_apply_pending_req(
 	void *priv, void *data)
 {
 	int rc = 0;
@@ -2323,13 +2323,22 @@ static int __cam_isp_ctx_apply_req_offline(
 		goto end;
 	}
 
-	if ((ctx->state != CAM_CTX_ACTIVATED) ||
-		(!atomic_read(&ctx_isp->rxd_epoch)) ||
-		(ctx_isp->substate_activated == CAM_ISP_CTX_ACTIVATED_APPLIED))
-		goto end;
+	if (ctx_isp->vfps_aux_context) {
+		if (ctx_isp->substate_activated == CAM_ISP_CTX_ACTIVATED_APPLIED)
+			goto end;
+
+		if (ctx_isp->active_req_cnt >= 1)
+			goto end;
+	} else {
+		if ((ctx->state != CAM_CTX_ACTIVATED) ||
+			(!atomic_read(&ctx_isp->rxd_epoch)) ||
+			(ctx_isp->substate_activated == CAM_ISP_CTX_ACTIVATED_APPLIED))
+			goto end;
+
+		if (ctx_isp->active_req_cnt >= 2)
+			goto end;
+	}
 
-	if (ctx_isp->active_req_cnt >= 2)
-		goto end;
 
 	spin_lock_bh(&ctx->lock);
 	req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request,
@@ -2395,7 +2404,7 @@ end:
 	return rc;
 }
 
-static int __cam_isp_ctx_schedule_apply_req_offline(
+static int __cam_isp_ctx_schedule_apply_req(
 	struct cam_isp_context *ctx_isp)
 {
 	int rc = 0;
@@ -2407,7 +2416,7 @@ static int __cam_isp_ctx_schedule_apply_req_offline(
 		return -ENOMEM;
 	}
 
-	task->process_cb = __cam_isp_ctx_apply_req_offline;
+	task->process_cb = __cam_isp_ctx_apply_pending_req;
 	rc = cam_req_mgr_workq_enqueue_task(task, ctx_isp, CRM_TASK_PRIORITY_0);
 	if (rc)
 		CAM_ERR(CAM_ISP, "Failed to schedule task rc:%d", rc);
@@ -2444,7 +2453,7 @@ static int __cam_isp_ctx_offline_epoch_in_activated_state(
 		}
 	}
 
-	__cam_isp_ctx_schedule_apply_req_offline(ctx_isp);
+	__cam_isp_ctx_schedule_apply_req(ctx_isp);
 
 	/*
 	 * If no valid request, wait for RUP shutter posted after buf done
@@ -5872,6 +5881,7 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx,
 	ctx_isp->hw_acquired = false;
 	ctx_isp->init_received = false;
 	ctx_isp->offline_context = false;
+	ctx_isp->vfps_aux_context = false;
 	ctx_isp->rdi_only_context = false;
 	ctx_isp->req_info.last_bufdone_req_id = 0;
 	ctx_isp->v4l2_event_sub_ids = 0;
@@ -6046,7 +6056,7 @@ static int __cam_isp_ctx_config_dev_in_top_state(
 			goto put_ref;
 		}
 
-		if (ctx_isp->offline_context) {
+		if ((ctx_isp->offline_context) || (ctx_isp->vfps_aux_context)) {
 			__cam_isp_ctx_enqueue_request_in_order(ctx, req, true);
 		} else if (ctx->ctx_crm_intf->add_req) {
 			memset(&add_req, 0, sizeof(add_req));
@@ -6078,9 +6088,11 @@ static int __cam_isp_ctx_config_dev_in_top_state(
 		"Preprocessing Config req_id %lld successful on ctx %u",
 		req->request_id, ctx->ctx_id);
 
-	if (ctx_isp->offline_context && atomic_read(&ctx_isp->rxd_epoch)) {
-		__cam_isp_ctx_schedule_apply_req_offline(ctx_isp);
-	}
+	if (ctx_isp->offline_context && atomic_read(&ctx_isp->rxd_epoch))
+		__cam_isp_ctx_schedule_apply_req(ctx_isp);
+	else if (ctx_isp->vfps_aux_context &&
+		(req_isp->hw_update_data.packet_opcode_type != CAM_ISP_PACKET_INIT_DEV))
+		__cam_isp_ctx_schedule_apply_req(ctx_isp);
 
 	return rc;
 
@@ -6537,7 +6549,7 @@ end:
 	return rc;
 }
 
-static void cam_req_mgr_process_workq_offline_ife_worker(struct work_struct *w)
+static void cam_req_mgr_process_workq_apply_req_worker(struct work_struct *w)
 {
 	cam_req_mgr_process_workq(w);
 }
@@ -6685,14 +6697,6 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx,
 			cam_isp_ctx_offline_state_machine_irq;
 		ctx_isp->substate_machine = NULL;
 		ctx_isp->offline_context = true;
-
-		rc = cam_req_mgr_workq_create("offline_ife", 20,
-			&ctx_isp->workq, CRM_WORKQ_USAGE_IRQ, 0,
-			cam_req_mgr_process_workq_offline_ife_worker);
-		if (rc)
-			CAM_ERR(CAM_ISP,
-				"Failed to create workq for offline IFE rc:%d",
-				rc);
 	} else {
 		CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources");
 		ctx_isp->substate_machine_irq =
@@ -6701,6 +6705,17 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx,
 			cam_isp_ctx_activated_state_machine;
 	}
 
+	if (ctx_isp->offline_context || ctx_isp->vfps_aux_context) {
+		rc = cam_req_mgr_workq_create("ife_apply_req", 20,
+			&ctx_isp->workq, CRM_WORKQ_USAGE_IRQ, 0,
+			cam_req_mgr_process_workq_apply_req_worker);
+		if (rc)
+			CAM_ERR(CAM_ISP,
+				"Failed to create workq for IFE rc:%d offline: %s vfps: %s",
+				rc, CAM_BOOL_TO_YESNO(ctx_isp->offline_context),
+				CAM_BOOL_TO_YESNO(ctx_isp->vfps_aux_context));
+	}
+
 	ctx_isp->hw_ctx = param.ctxt_to_hw_map;
 	ctx_isp->hw_acquired = true;
 	ctx->ctxt_to_hw_map = param.ctxt_to_hw_map;
@@ -7450,9 +7465,20 @@ static int __cam_isp_ctx_process_evt(struct cam_context *ctx,
 	struct cam_req_mgr_link_evt_data *link_evt_data)
 {
 	int rc = 0;
+	struct cam_isp_context *ctx_isp =
+		(struct cam_isp_context *) ctx->ctx_priv;
+
+	if ((ctx->state == CAM_CTX_ACQUIRED) &&
+		(link_evt_data->evt_type != CAM_REQ_MGR_LINK_EVT_UPDATE_PROPERTIES)) {
+		CAM_WARN(CAM_ISP,
+			"Get unexpect evt:%d in acquired state",
+			link_evt_data->evt_type);
+		return -EINVAL;
+	}
 
 	switch (link_evt_data->evt_type) {
 	case CAM_REQ_MGR_LINK_EVT_ERR:
+	case CAM_REQ_MGR_LINK_EVT_EOF:
 		/* No handling */
 		break;
 	case CAM_REQ_MGR_LINK_EVT_PAUSE:
@@ -7480,6 +7506,15 @@ static int __cam_isp_ctx_process_evt(struct cam_context *ctx,
 		link_evt_data->try_for_recovery = internal_recovery_skipped;
 	}
 		break;
+	case CAM_REQ_MGR_LINK_EVT_UPDATE_PROPERTIES:
+		if (link_evt_data->u.properties_mask &
+			CAM_LINK_PROPERTY_SENSOR_STANDBY_AFTER_EOF)
+			ctx_isp->vfps_aux_context = true;
+		else
+			ctx_isp->vfps_aux_context = false;
+		CAM_DBG(CAM_ISP, "vfps_aux_context:%s on ctx: %u",
+			CAM_BOOL_TO_YESNO(ctx_isp->vfps_aux_context), ctx->ctx_id);
+		break;
 	default:
 		CAM_WARN(CAM_ISP,
 			"Unsupported event type: 0x%x on ctx: %u",
@@ -7721,6 +7756,7 @@ static struct cam_ctx_ops
 			.link = __cam_isp_ctx_link_in_acquired,
 			.unlink = __cam_isp_ctx_unlink_in_acquired,
 			.get_dev_info = __cam_isp_ctx_get_dev_info_in_acquired,
+			.process_evt = __cam_isp_ctx_process_evt,
 			.flush_req = __cam_isp_ctx_flush_req_in_top_state,
 			.dump_req = __cam_isp_ctx_dump_in_top_state,
 		},

+ 3 - 0
drivers/cam_isp/cam_isp_context.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CAM_ISP_CONTEXT_H_
@@ -269,6 +270,7 @@ struct cam_isp_context_event_record {
  * @rdi_only_context:          Get context type information.
  *                             true, if context is rdi only context
  * @offline_context:           Indicate whether context is for offline IFE
+ * @vfps_aux_context:          Indicate whether context is for VFPS aux link
  * @hw_acquired:               Indicate whether HW resources are acquired
  * @init_received:             Indicate whether init config packet is received
  * @split_acquire:             Indicate whether a separate acquire is expected
@@ -324,6 +326,7 @@ struct cam_isp_context {
 		CAM_ISP_CTX_EVENT_MAX][CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES];
 	bool                                  rdi_only_context;
 	bool                                  offline_context;
+	bool                                  vfps_aux_context;
 	bool                                  hw_acquired;
 	bool                                  init_received;
 	bool                                  split_acquire;

+ 103 - 4
drivers/cam_req_mgr/cam_req_mgr_core.c

@@ -70,6 +70,7 @@ void cam_req_mgr_core_link_reset(struct cam_req_mgr_core_link *link)
 	link->wq_congestion = false;
 	link->try_for_internal_recovery = false;
 	atomic_set(&link->eof_event_cnt, 0);
+	link->properties_mask = CAM_LINK_PROPERTY_NONE;
 	__cam_req_mgr_reset_apply_data(link);
 
 	for (i = 0; i < MAXIMUM_LINKS_PER_SESSION - 1; i++)
@@ -3156,6 +3157,37 @@ end:
 	return rc;
 }
 
+/**
+ * cam_req_mgr_notify_eof_event()
+ *
+ * @brief  : This runs in workqueue thread context. Call core funcs to
+ *           notify eof event to sub devices.
+ * @link   : link info
+ *
+ */
+static void cam_req_mgr_notify_eof_event(struct cam_req_mgr_core_link *link)
+{
+	int                                  i;
+	struct cam_req_mgr_connected_device *dev = NULL;
+	struct cam_req_mgr_link_evt_data     evt_data;
+
+	for (i = 0; i < link->num_devs; i++) {
+		dev = &link->l_dev[i];
+		if (!dev)
+			continue;
+
+		evt_data.dev_hdl = dev->dev_hdl;
+		evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_EOF;
+		evt_data.link_hdl = link->link_hdl;
+
+		if (dev->ops && dev->ops->process_evt)
+			dev->ops->process_evt(&evt_data);
+	}
+
+	CAM_DBG(CAM_CRM, "Notify EOF event done on link:0x%x",
+		link->link_hdl);
+}
+
 /**
  * cam_req_mgr_process_trigger()
  *
@@ -3222,6 +3254,9 @@ static int cam_req_mgr_process_trigger(void *priv, void *data)
 
 			__cam_req_mgr_reset_req_slot(link, idx);
 		}
+	} else if (trigger_data->trigger == CAM_TRIGGER_POINT_EOF) {
+		if (link->properties_mask & CAM_LINK_PROPERTY_SENSOR_STANDBY_AFTER_EOF)
+			cam_req_mgr_notify_eof_event(link);
 	}
 
 	/*
@@ -3657,10 +3692,12 @@ static int cam_req_mgr_cb_notify_trigger(
 	 * Reduce the workq overhead when there is
 	 * not any eof event found.
 	 */
-	if ((!atomic_read(&link->eof_event_cnt)) &&
-		(trigger == CAM_TRIGGER_POINT_EOF)) {
-		CAM_DBG(CAM_CRM, "Not any request to schedule at EOF");
-		goto end;
+	if (trigger == CAM_TRIGGER_POINT_EOF) {
+		if (!atomic_read(&link->eof_event_cnt) &&
+			!(link->properties_mask & CAM_LINK_PROPERTY_SENSOR_STANDBY_AFTER_EOF)) {
+			CAM_DBG(CAM_CRM, "No any request to schedule at EOF");
+			goto end;
+		}
 	}
 
 	spin_lock_bh(&link->link_state_spin_lock);
@@ -4709,6 +4746,68 @@ end:
 	return rc;
 }
 
+int cam_req_mgr_link_properties(struct cam_req_mgr_link_properties *properties)
+{
+	int                                    i, rc = 0;
+	struct cam_req_mgr_core_link          *link = NULL;
+	struct cam_req_mgr_connected_device   *dev;
+	struct cam_req_mgr_link_evt_data       evt_data;
+
+	mutex_lock(&g_crm_core_dev->crm_lock);
+	link = (struct cam_req_mgr_core_link *)
+		cam_get_device_priv(properties->link_hdl);
+	if (!link || (link->link_hdl != properties->link_hdl)) {
+		CAM_ERR(CAM_CRM, "link: %s, properties->link_hdl:0x%x, link->link_hdl:0x%x",
+			CAM_IS_NULL_TO_STR(link), properties->link_hdl,
+			(!link) ? CAM_REQ_MGR_DEFAULT_HDL_VAL : link->link_hdl);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	if (link->state != CAM_CRM_LINK_STATE_READY) {
+		CAM_ERR(CAM_CRM,
+			"Only can config link 0x%x properties in ready state",
+			link->link_hdl);
+		rc = -EAGAIN;
+		goto end;
+	}
+
+	mutex_lock(&link->lock);
+	link->properties_mask = properties->properties_mask;
+
+	for (i = 0; i < link->num_devs; i++) {
+		dev = &link->l_dev[i];
+
+		if (!dev)
+			continue;
+
+		evt_data.dev_hdl = dev->dev_hdl;
+		evt_data.link_hdl = link->link_hdl;
+		evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_UPDATE_PROPERTIES;
+		evt_data.u.properties_mask = link->properties_mask;
+
+		if (dev->ops && dev->ops->process_evt) {
+			rc = dev->ops->process_evt(&evt_data);
+			if (rc) {
+				CAM_ERR(CAM_CRM,
+					"Failed to set properties on link 0x%x dev 0x%x",
+					link->link_hdl, dev->dev_hdl);
+				mutex_unlock(&link->lock);
+				goto end;
+			}
+		}
+	}
+
+	mutex_unlock(&link->lock);
+
+	CAM_DBG(CAM_CRM, "link 0x%x set properties successfully, properties mask:0x%x",
+		link->link_hdl, link->properties_mask);
+
+end:
+	mutex_unlock(&g_crm_core_dev->crm_lock);
+	return rc;
+}
+
 int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req)
 {
 	int                                  rc = 0;

+ 10 - 0
drivers/cam_req_mgr/cam_req_mgr_core.h

@@ -393,6 +393,7 @@ struct cam_req_mgr_connected_device {
  * @last_sof_trigger_jiffies : Record the jiffies of last sof trigger jiffies
  * @wq_congestion        : Indicates if WQ congestion is detected or not
  * @try_for_internal_recovery : If the link stalls try for RT internal recovery
+ * @properties_mask      : Indicates if current link enables some special properties
  */
 struct cam_req_mgr_core_link {
 	int32_t                              link_hdl;
@@ -432,6 +433,7 @@ struct cam_req_mgr_core_link {
 	uint64_t                             last_sof_trigger_jiffies;
 	bool                                 wq_congestion;
 	bool                                 try_for_internal_recovery;
+	uint32_t                             properties_mask;
 };
 
 /**
@@ -671,4 +673,12 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control);
  * @dump_req: Dump request
  */
 int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req);
+
+/**
+ * cam_req_mgr_link_properties()
+ * @brief:   Handles link properties
+ * @properties: Link properties
+ */
+int cam_req_mgr_link_properties(struct cam_req_mgr_link_properties *properties);
+
 #endif

+ 16 - 0
drivers/cam_req_mgr/cam_req_mgr_dev.c

@@ -613,6 +613,22 @@ static long cam_private_ioctl(struct file *file, void *fh,
 			rc = -EFAULT;
 		}
 		break;
+	case CAM_REQ_MGR_LINK_PROPERTIES: {
+		struct cam_req_mgr_link_properties cmd;
+
+		if (k_ioctl->size != sizeof(cmd))
+			return -EINVAL;
+
+		if (copy_from_user(&cmd,
+			u64_to_user_ptr(k_ioctl->handle),
+			sizeof(struct cam_req_mgr_link_properties))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		rc = cam_req_mgr_link_properties(&cmd);
+		}
+		break;
 	default:
 		return -ENOIOCTLCMD;
 	}

+ 20 - 12
drivers/cam_req_mgr/cam_req_mgr_interface.h

@@ -197,16 +197,20 @@ enum cam_req_mgr_device_id {
 
 /**
  * enum cam_req_mgr_link_evt_type
- * @CAM_REQ_MGR_LINK_EVT_ERR             : error on the link from any of the
- *                                         connected devices
- * @CAM_REQ_MGR_LINK_EVT_PAUSE           : to pause the link
- * @CAM_REQ_MGR_LINK_EVT_RESUME          : resumes the link which was paused
- * @CAM_REQ_MGR_LINK_EVT_SOF_FREEZE      : request manager has detected an
- *                                         sof freeze
- * @CAM_REQ_MGR_LINK_EVT_STALLED         : Indicate to all connected devices
- *                                         that the pipeline is stalled.
- *                                         Devices can handle accordingly
- * @CAM_REQ_MGR_LINK_EVT_MAX             : invalid event type
+ * @CAM_REQ_MGR_LINK_EVT_ERR               : error on the link from any of the
+ *                                           connected devices
+ * @CAM_REQ_MGR_LINK_EVT_PAUSE             : to pause the link
+ * @CAM_REQ_MGR_LINK_EVT_RESUME            : resumes the link which was paused
+ * @CAM_REQ_MGR_LINK_EVT_SOF_FREEZE        : request manager has detected an
+ *                                           sof freeze
+ * @CAM_REQ_MGR_LINK_EVT_STALLED           : Indicate to all connected devices
+ *                                           that the pipeline is stalled.
+ *                                           Devices can handle accordingly
+ * @CAM_REQ_MGR_LINK_EVT_EOF               : Indicate to all connected devices
+ *                                           that we get an EOF
+ * @CAM_REQ_MGR_LINK_EVT_UPDATE_PROPERTIES : Notify sub devices of the properties
+ *                                           updating
+ * @CAM_REQ_MGR_LINK_EVT_MAX               : invalid event type
  */
 enum cam_req_mgr_link_evt_type {
 	CAM_REQ_MGR_LINK_EVT_ERR,
@@ -214,6 +218,8 @@ enum cam_req_mgr_link_evt_type {
 	CAM_REQ_MGR_LINK_EVT_RESUME,
 	CAM_REQ_MGR_LINK_EVT_SOF_FREEZE,
 	CAM_REQ_MGR_LINK_EVT_STALLED,
+	CAM_REQ_MGR_LINK_EVT_EOF,
+	CAM_REQ_MGR_LINK_EVT_UPDATE_PROPERTIES,
 	CAM_REQ_MGR_LINK_EVT_MAX,
 };
 
@@ -291,7 +297,6 @@ struct cam_req_mgr_add_request {
 	bool     trigger_eof;
 };
 
-
 /**
  * struct cam_req_mgr_notify_stop
  * @link_hdl             : link identifier
@@ -377,9 +382,11 @@ struct cam_req_mgr_flush_request {
  * struct cam_req_mgr_event_data
  * @link_hdl          : link handle
  * @req_id            : request id
- * @evt_type          : link event
  * @try_for_recovery  : Link is stalled allow subdevices to recover if
  *                      possible
+ * @evt_type          : link event
+ * @error             : error code
+ * @properties_mask   : properties mask
  */
 struct cam_req_mgr_link_evt_data {
 	int32_t  link_hdl;
@@ -389,6 +396,7 @@ struct cam_req_mgr_link_evt_data {
 	enum cam_req_mgr_link_evt_type evt_type;
 	union {
 		enum cam_req_mgr_device_error error;
+		uint32_t properties_mask;
 	} u;
 };
 

+ 138 - 29
drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c

@@ -12,9 +12,42 @@
 #include "cam_trace.h"
 #include "cam_common_util.h"
 #include "cam_packet_util.h"
+#include "cam_req_mgr_dev.h"
 
 extern struct completion *cam_sensor_get_i3c_completion(uint32_t index);
 
+static int cam_sensor_notify_v4l2_error_event(
+	struct cam_sensor_ctrl_t *s_ctrl,
+	uint32_t error_type, uint32_t error_code)
+{
+	int                        rc = 0;
+	struct cam_req_mgr_message req_msg;
+
+	req_msg.session_hdl = s_ctrl->bridge_intf.session_hdl;
+	req_msg.u.err_msg.device_hdl = s_ctrl->bridge_intf.device_hdl;
+	req_msg.u.err_msg.link_hdl = s_ctrl->bridge_intf.link_hdl;
+	req_msg.u.err_msg.error_type = error_type;
+	req_msg.u.err_msg.request_id = s_ctrl->last_applied_req;
+	req_msg.u.err_msg.resource_size = 0x0;
+	req_msg.u.err_msg.error_code = error_code;
+
+	CAM_DBG(CAM_SENSOR,
+		"v4l2 error event [type: %u code: %u] for req: %llu on %s",
+		error_type, error_code, s_ctrl->last_applied_req,
+		s_ctrl->sensor_name);
+
+	rc = cam_req_mgr_notify_message(&req_msg,
+		V4L_EVENT_CAM_REQ_MGR_ERROR,
+		V4L_EVENT_CAM_REQ_MGR_EVENT);
+	if (rc)
+		CAM_ERR(CAM_SENSOR,
+			"Notifying v4l2 error [type: %u code: %u] failed for req id:%llu on %s",
+			error_type, error_code, s_ctrl->last_applied_req,
+			s_ctrl->sensor_name);
+
+	return rc;
+}
+
 static int cam_sensor_update_req_mgr(
 	struct cam_sensor_ctrl_t *s_ctrl,
 	struct cam_packet *csl_packet)
@@ -783,6 +816,48 @@ int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl)
 	return rc;
 }
 
+int cam_sensor_stream_off(struct cam_sensor_ctrl_t *s_ctrl)
+{
+	int               rc = 0;
+	struct timespec64 ts;
+	uint64_t          ms, sec, min, hrs;
+
+	if (s_ctrl->sensor_state != CAM_SENSOR_START) {
+		rc = -EINVAL;
+		CAM_WARN(CAM_SENSOR,
+			"Not in right state to stop %s state: %d",
+			s_ctrl->sensor_name, s_ctrl->sensor_state);
+		goto end;
+	}
+
+	if (s_ctrl->i2c_data.streamoff_settings.is_settings_valid &&
+		(s_ctrl->i2c_data.streamoff_settings.request_id == 0)) {
+		rc = cam_sensor_apply_settings(s_ctrl, 0,
+			CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF);
+		if (rc < 0)
+			CAM_ERR(CAM_SENSOR,
+				"cannot apply streamoff settings for %s",
+				s_ctrl->sensor_name);
+	}
+
+	cam_sensor_release_per_frame_resource(s_ctrl);
+	s_ctrl->last_flush_req = 0;
+	s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE;
+
+	CAM_GET_TIMESTAMP(ts);
+	CAM_CONVERT_TIMESTAMP_FORMAT(ts, hrs, min, sec, ms);
+
+	CAM_INFO(CAM_SENSOR,
+		"%llu:%llu:%llu.%llu CAM_STOP_DEV Success for %s sensor_id:0x%x,sensor_slave_addr:0x%x",
+		hrs, min, sec, ms,
+		s_ctrl->sensor_name,
+		s_ctrl->sensordata->slave_info.sensor_id,
+		s_ctrl->sensordata->slave_info.sensor_slave_addr);
+
+end:
+	return rc;
+}
+
 int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl,
 	void *arg)
 {
@@ -1017,6 +1092,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl,
 
 		s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE;
 		s_ctrl->last_flush_req = 0;
+		s_ctrl->is_flushed = false;
 		CAM_INFO(CAM_SENSOR,
 			"CAM_ACQUIRE_DEV Success for %s sensor_id:0x%x,sensor_slave_addr:0x%x",
 			s_ctrl->sensor_name,
@@ -1150,38 +1226,15 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl,
 	}
 		break;
 	case CAM_STOP_DEV: {
-		if (s_ctrl->sensor_state != CAM_SENSOR_START) {
-			rc = -EINVAL;
-			CAM_WARN(CAM_SENSOR,
-			"Not in right state to stop %s state: %d",
-			s_ctrl->sensor_name, s_ctrl->sensor_state);
+		if ((s_ctrl->stream_off_after_eof) && (!s_ctrl->is_flushed)) {
+			CAM_DBG(CAM_SENSOR, "Ignore stop dev cmd for VFPS feature");
 			goto release_mutex;
 		}
 
-		if (s_ctrl->i2c_data.streamoff_settings.is_settings_valid &&
-			(s_ctrl->i2c_data.streamoff_settings.request_id == 0)) {
-			rc = cam_sensor_apply_settings(s_ctrl, 0,
-				CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF);
-			if (rc < 0) {
-				CAM_ERR(CAM_SENSOR,
-				"cannot apply streamoff settings for %s",
-				s_ctrl->sensor_name);
-			}
-		}
-
-		cam_sensor_release_per_frame_resource(s_ctrl);
-		s_ctrl->last_flush_req = 0;
-		s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE;
-
-		CAM_GET_TIMESTAMP(ts);
-		CAM_CONVERT_TIMESTAMP_FORMAT(ts, hrs, min, sec, ms);
-
-		CAM_INFO(CAM_SENSOR,
-			"%llu:%llu:%llu.%llu CAM_STOP_DEV Success for %s sensor_id:0x%x,sensor_slave_addr:0x%x",
-			hrs, min, sec, ms,
-			s_ctrl->sensor_name,
-			s_ctrl->sensordata->slave_info.sensor_id,
-			s_ctrl->sensordata->slave_info.sensor_slave_addr);
+		rc = cam_sensor_stream_off(s_ctrl);
+		if (rc)
+			goto release_mutex;
+		s_ctrl->is_flushed = false;
 	}
 		break;
 	case CAM_CONFIG_DEV: {
@@ -1578,6 +1631,8 @@ int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl,
 				"Invalid/NOP request to apply: %lld", req_id);
 		}
 
+		s_ctrl->last_applied_req = req_id;
+
 		/* Change the logic dynamically */
 		for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) {
 			if ((req_id >=
@@ -1769,6 +1824,60 @@ int32_t cam_sensor_flush_request(struct cam_req_mgr_flush_request *flush_req)
 		CAM_DBG(CAM_SENSOR,
 			"Flush request id:%lld not found in the pending list",
 			flush_req->req_id);
+
+	if (s_ctrl->stream_off_after_eof)
+		s_ctrl->is_flushed = true;
+
+	mutex_unlock(&(s_ctrl->cam_sensor_mutex));
+	return rc;
+}
+
+int cam_sensor_process_evt(struct cam_req_mgr_link_evt_data *evt_data)
+{
+	int                       rc = 0;
+	struct cam_sensor_ctrl_t *s_ctrl = NULL;
+
+	if (!evt_data)
+		return -EINVAL;
+
+	s_ctrl = (struct cam_sensor_ctrl_t *)
+		cam_get_device_priv(evt_data->dev_hdl);
+	if (!s_ctrl) {
+		CAM_ERR(CAM_SENSOR, "Device data is NULL");
+		return -EINVAL;
+	}
+
+	CAM_DBG(CAM_SENSOR, "Received evt:%d", evt_data->evt_type);
+
+	mutex_lock(&(s_ctrl->cam_sensor_mutex));
+
+	switch (evt_data->evt_type) {
+	case CAM_REQ_MGR_LINK_EVT_EOF:
+		if (s_ctrl->stream_off_after_eof) {
+			rc = cam_sensor_stream_off(s_ctrl);
+			if (rc) {
+				CAM_ERR(CAM_SENSOR, "Failed to stream off %s",
+					s_ctrl->sensor_name);
+
+				cam_sensor_notify_v4l2_error_event(s_ctrl,
+					CAM_REQ_MGR_ERROR_TYPE_FULL_RECOVERY,
+					CAM_REQ_MGR_SENSOR_STREAM_OFF_FAILED);
+			}
+		}
+		break;
+	case CAM_REQ_MGR_LINK_EVT_UPDATE_PROPERTIES:
+		if (evt_data->u.properties_mask &
+			CAM_LINK_PROPERTY_SENSOR_STANDBY_AFTER_EOF)
+			s_ctrl->stream_off_after_eof = true;
+		else
+			s_ctrl->stream_off_after_eof = false;
+		break;
+	default:
+		/* No handling */
+		break;
+	}
+
 	mutex_unlock(&(s_ctrl->cam_sensor_mutex));
+
 	return rc;
 }

+ 8 - 0
drivers/cam_sensor_module/cam_sensor/cam_sensor_core.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2017-2018,2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CAM_SENSOR_CORE_H_
@@ -75,6 +76,13 @@ int cam_sensor_publish_dev_info(struct cam_req_mgr_device_info *info);
  */
 int cam_sensor_establish_link(struct cam_req_mgr_core_dev_link_setup *link);
 
+/**
+ * @evt_data: Event data info
+ *
+ * This API processes the event which is published by request mgr
+ */
+int cam_sensor_process_evt(struct cam_req_mgr_link_evt_data *evt_data);
+
 /**
  * @s_ctrl: Sensor ctrl structure
  * @arg:    Camera control command argument

+ 1 - 0
drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c

@@ -452,6 +452,7 @@ static int cam_sensor_component_bind(struct device *dev,
 	s_ctrl->bridge_intf.ops.notify_frame_skip =
 		cam_sensor_notify_frame_skip;
 	s_ctrl->bridge_intf.ops.flush_req = cam_sensor_flush_request;
+	s_ctrl->bridge_intf.ops.process_evt = cam_sensor_process_evt;
 
 	s_ctrl->sensordata->power_info.dev = &pdev->dev;
 	platform_set_drvdata(pdev, s_ctrl);

+ 6 - 0
drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h

@@ -82,6 +82,9 @@ struct sensor_intf_params {
  * @pipeline_delay: Sensor pipeline delay
  * @sensor_name: Sensor name
  * @aon_camera_id: AON Camera ID associated with this sensor
+ * @last_applied_req: Last applied request id
+ * @is_flushed: Indicate if the request has been flushed
+ * @stream_off_after_eof: Indicates if sensor needs to stream off after eof
  */
 struct cam_sensor_ctrl_t {
 	char                           device_name[CAM_CTX_DEV_NAME_MAX_LENGTH];
@@ -111,6 +114,9 @@ struct cam_sensor_ctrl_t {
 	uint16_t                       pipeline_delay;
 	char                           sensor_name[CAM_SENSOR_NAME_MAX_SIZE];
 	uint8_t                        aon_camera_id;
+	int64_t                        last_applied_req;
+	bool                           is_flushed;
+	bool                           stream_off_after_eof;
 };
 
 /**