瀏覽代碼

msm: camera: common: Enabling EOF support for flash

New usecase for flash driver requires to be trigger at EOF.
This change adds the new operation code support in flash
driver along with EOF enable support in crm and across
other drivers. Also to improve the performance, this change
adds the logic to dynamically update the subscribe event to
CRM, so that CRM can enqueue EOF events when Flash or any other
device add the request for EOF.

CRs-Fixed: 2633194
Change-Id: I2f68ac7fc6a4699debd39b64319728cdf17bbcfa
Signed-off-by: Jigarkumar Zala <[email protected]>
Jigarkumar Zala 5 年之前
父節點
當前提交
438fc6a877

+ 3 - 1
drivers/cam_isp/cam_isp_context.c

@@ -3910,6 +3910,7 @@ static int __cam_isp_ctx_config_dev_in_top_state(
 			add_req.dev_hdl  = ctx->dev_hdl;
 			add_req.req_id   = req->request_id;
 			add_req.skip_before_applying = 0;
+			add_req.trigger_eof = false;
 			rc = ctx->ctx_crm_intf->add_req(&add_req);
 			if (rc) {
 				CAM_ERR(CAM_ISP, "Add req failed: req id=%llu",
@@ -4525,7 +4526,8 @@ static int __cam_isp_ctx_link_in_acquired(struct cam_context *ctx,
 
 	ctx->link_hdl = link->link_hdl;
 	ctx->ctx_crm_intf = link->crm_cb;
-	ctx_isp->subscribe_event = link->subscribe_event;
+	ctx_isp->subscribe_event =
+		CAM_TRIGGER_POINT_SOF | CAM_TRIGGER_POINT_EOF;
 	ctx_isp->trigger_id = link->trigger_id;
 
 	/* change state only if we had the init config */

+ 142 - 27
drivers/cam_req_mgr/cam_req_mgr_core.c

@@ -49,6 +49,7 @@ void cam_req_mgr_core_link_reset(struct cam_req_mgr_core_link *link)
 	link->initial_skip = true;
 	link->sof_timestamp = 0;
 	link->prev_sof_timestamp = 0;
+	atomic_set(&link->eof_event_cnt, 0);
 }
 
 void cam_req_mgr_handle_core_shutdown(void)
@@ -456,10 +457,15 @@ static void __cam_req_mgr_flush_req_slot(
 				tbl->pd, idx, tbl->slot[idx].state);
 			tbl->slot[idx].req_ready_map = 0;
 			tbl->slot[idx].state = CRM_REQ_STATE_EMPTY;
+			tbl->slot[idx].ops.apply_at_eof = false;
+			tbl->slot[idx].ops.skip_next_frame = false;
+			tbl->slot[idx].ops.dev_hdl = -1;
+			tbl->slot[idx].ops.is_applied = false;
 			tbl = tbl->next;
 		}
 	}
 
+	atomic_set(&link->eof_event_cnt, 0);
 	in_q->wr_idx = 0;
 	in_q->rd_idx = 0;
 }
@@ -502,6 +508,10 @@ static void __cam_req_mgr_reset_req_slot(struct cam_req_mgr_core_link *link,
 			tbl->pd, idx, tbl->slot[idx].state);
 		tbl->slot[idx].req_ready_map = 0;
 		tbl->slot[idx].state = CRM_REQ_STATE_EMPTY;
+		tbl->slot[idx].ops.apply_at_eof = false;
+		tbl->slot[idx].ops.skip_next_frame = false;
+		tbl->slot[idx].ops.dev_hdl = -1;
+		tbl->slot[idx].ops.is_applied = false;
 		tbl = tbl->next;
 	}
 }
@@ -668,6 +678,10 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link,
 			apply_req.re_apply = true;
 	}
 
+	/*
+	 * This For loop is to address the special operation requested
+	 * by device
+	 */
 	for (i = 0; i < link->num_devs; i++) {
 		dev = &link->l_dev[i];
 		if (!dev)
@@ -681,37 +695,76 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link,
 
 		idx = link->req.apply_data[pd].idx;
 		slot = &dev->pd_tbl->slot[idx];
-		/*
-		 * Just let flash go for this request and other
-		 * device get restricted
-		 */
 
-		if ((slot->skip_next_frame != true) ||
-			(slot->dev_hdl != dev->dev_hdl))
+		if (slot->ops.dev_hdl < 0) {
+			CAM_DBG(CAM_CRM,
+				"No special ops detected for this table slot");
 			continue;
+		}
 
-		if (!(dev->dev_info.trigger & trigger))
+		if (slot->ops.apply_at_eof && slot->ops.skip_next_frame) {
+			CAM_ERR(CAM_CRM,
+				"Both EOF and SOF trigger is not supported");
+			return -EINVAL;
+		}
+
+		if (dev->dev_hdl != slot->ops.dev_hdl) {
+			CAM_DBG(CAM_CRM,
+				"Dev_hdl : %d Not matched:: Expected dev_hdl: %d",
+				dev->dev_hdl, slot->ops.dev_hdl);
 			continue;
+		}
+
+		/* This one is to prevent EOF request to apply on SOF*/
+		if ((trigger == CAM_TRIGGER_POINT_SOF) &&
+			(slot->ops.apply_at_eof)) {
+			CAM_DBG(CAM_CRM, "EOF event cannot be applied at SOF");
+			break;
+		}
+
+		if ((trigger == CAM_TRIGGER_POINT_EOF) &&
+			(!slot->ops.apply_at_eof)) {
+			CAM_DBG(CAM_CRM, "NO EOF DATA FOR REQ: %llu",
+				link->req.apply_data[pd].req_id);
+			break;
+		}
 
 		apply_req.dev_hdl = dev->dev_hdl;
 		apply_req.request_id =
 			link->req.apply_data[pd].req_id;
 		apply_req.trigger_point = trigger;
-		if (dev->ops && dev->ops->apply_req) {
+		if ((dev->ops) && (dev->ops->apply_req) &&
+			(!slot->ops.is_applied)) {
 			rc = dev->ops->apply_req(&apply_req);
 			if (rc) {
 				*failed_dev = dev;
 				return rc;
 			}
-			CAM_DBG(CAM_REQ,
-				"SEND: link_hdl: %x pd: %d req_id %lld",
-				link->link_hdl, pd, apply_req.request_id);
-			slot->skip_next_frame = false;
-			slot->is_applied = true;
+		}
+
+		CAM_DBG(CAM_REQ,
+			"SEND: link_hdl: %x pd: %d req_id %lld",
+			link->link_hdl, pd, apply_req.request_id);
+
+		if (trigger == CAM_TRIGGER_POINT_SOF &&
+			slot->ops.skip_next_frame) {
+			slot->ops.skip_next_frame = false;
+			slot->ops.is_applied = true;
 			return -EAGAIN;
+		} else if ((trigger == CAM_TRIGGER_POINT_EOF) &&
+			(slot->ops.apply_at_eof)) {
+			slot->ops.apply_at_eof = false;
+			if (atomic_read(&link->eof_event_cnt) > 0)
+				atomic_dec(&link->eof_event_cnt);
+			CAM_DBG(CAM_REQ,
+				"Req_id: %llu eof_event_cnt : %d",
+				link->req.apply_data[pd].req_id,
+				link->eof_event_cnt);
+			return 0;
 		}
 	}
 
+	/* For regular send requests */
 	for (i = 0; i < link->num_devs; i++) {
 		dev = &link->l_dev[i];
 		if (dev) {
@@ -739,12 +792,29 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link,
 			apply_req.report_if_bubble =
 				in_q->slot[idx].recover;
 
-			if ((slot->dev_hdl == dev->dev_hdl) &&
-				(slot->is_applied == true)) {
-				slot->is_applied = false;
+			if ((slot->ops.dev_hdl == dev->dev_hdl) &&
+				(slot->ops.is_applied)) {
+				slot->ops.is_applied = false;
 				continue;
 			}
 
+			/*
+			 * If apply_at_eof is enabled do not apply at SOF
+			 * e.x. Flash device
+			 */
+			if ((trigger == CAM_TRIGGER_POINT_SOF) &&
+				(dev->dev_hdl == slot->ops.dev_hdl) &&
+				(slot->ops.apply_at_eof))
+				continue;
+
+			/*
+			 * If apply_at_eof is not enabled ignore EOF
+			 */
+			if ((trigger == CAM_TRIGGER_POINT_EOF) &&
+				(dev->dev_hdl == slot->ops.dev_hdl) &&
+				(!slot->ops.apply_at_eof))
+				continue;
+
 			apply_req.trigger_point = trigger;
 			CAM_DBG(CAM_REQ,
 				"SEND: link_hdl: %x pd %d req_id %lld",
@@ -1507,6 +1577,13 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link,
 		if (link->trigger_mask == link->subscribe_event) {
 			slot->status = CRM_SLOT_STATUS_REQ_APPLIED;
 			link->trigger_mask = 0;
+			if (!(atomic_read(&link->eof_event_cnt)) &&
+				(trigger == CAM_TRIGGER_POINT_EOF)) {
+				link->subscribe_event &= ~CAM_TRIGGER_POINT_EOF;
+				CAM_DBG(CAM_CRM,
+					"Update link subscribe_event: %d",
+					link->subscribe_event);
+			}
 			CAM_DBG(CAM_CRM, "req %d is applied on link %x",
 				slot->req_id,
 				link->link_hdl);
@@ -1591,11 +1668,19 @@ static void __cam_req_mgr_add_tbl_to_link(struct cam_req_mgr_req_tbl **l_tbl,
  */
 static struct cam_req_mgr_req_tbl *__cam_req_mgr_create_pd_tbl(int32_t delay)
 {
+	int i = 0;
+
 	struct cam_req_mgr_req_tbl *tbl =
 		kzalloc(sizeof(struct cam_req_mgr_req_tbl), GFP_KERNEL);
 	if (tbl != NULL) {
 		tbl->num_slots = MAX_REQ_SLOTS;
 		CAM_DBG(CAM_CRM, "pd= %d slots= %d", delay, tbl->num_slots);
+		for (i = 0; i < MAX_REQ_SLOTS; i++) {
+			tbl->slot[i].ops.apply_at_eof = false;
+			tbl->slot[i].ops.skip_next_frame = false;
+			tbl->slot[i].ops.dev_hdl = -1;
+			tbl->slot[i].ops.is_applied = false;
+		}
 	}
 
 	return tbl;
@@ -2310,17 +2395,27 @@ int cam_req_mgr_process_add_req(void *priv, void *data)
 	}
 
 	slot = &tbl->slot[idx];
-	slot->is_applied = false;
+	slot->ops.is_applied = false;
 	if ((add_req->skip_before_applying & 0xFF) > slot->inject_delay) {
 		slot->inject_delay = (add_req->skip_before_applying & 0xFF);
-		slot->dev_hdl = add_req->dev_hdl;
-		if (add_req->skip_before_applying & SKIP_NEXT_FRAME)
-			slot->skip_next_frame = true;
+		if (add_req->skip_before_applying & SKIP_NEXT_FRAME) {
+			slot->ops.skip_next_frame = true;
+			slot->ops.dev_hdl = add_req->dev_hdl;
+		}
 		CAM_DBG(CAM_CRM, "Req_id %llu injecting delay %llu",
 			add_req->req_id,
 			(add_req->skip_before_applying & 0xFF));
 	}
 
+	/* Used when Precise Flash is enabled */
+	if ((add_req->trigger_eof) && (!add_req->skip_before_applying)) {
+		slot->ops.apply_at_eof = true;
+		slot->ops.dev_hdl = add_req->dev_hdl;
+		CAM_DBG(CAM_REQ,
+			"Req_id %llu added for EOF tigger for Device: %s",
+			add_req->req_id, device->dev_info.name);
+	}
+
 	if (slot->state != CRM_REQ_STATE_PENDING &&
 		slot->state != CRM_REQ_STATE_EMPTY) {
 		CAM_WARN(CAM_CRM,
@@ -2658,9 +2753,10 @@ static int cam_req_mgr_cb_add_req(struct cam_req_mgr_add_request *add_req)
 		return -EINVAL;
 	}
 
-	CAM_DBG(CAM_REQ, "dev name %s dev_hdl %d dev req %lld",
+	CAM_DBG(CAM_REQ,
+		"dev name %s dev_hdl %d dev req %lld, trigger_eof: %d",
 		__cam_req_mgr_dev_handle_to_name(add_req->dev_hdl, link),
-		add_req->dev_hdl, add_req->req_id);
+		add_req->dev_hdl, add_req->req_id, add_req->trigger_eof);
 
 	mutex_lock(&link->lock);
 	spin_lock_bh(&link->link_state_spin_lock);
@@ -2695,6 +2791,16 @@ static int cam_req_mgr_cb_add_req(struct cam_req_mgr_add_request *add_req)
 	dev_req->link_hdl = add_req->link_hdl;
 	dev_req->dev_hdl = add_req->dev_hdl;
 	dev_req->skip_before_applying = add_req->skip_before_applying;
+	dev_req->trigger_eof = add_req->trigger_eof;
+	if (dev_req->trigger_eof) {
+		link->subscribe_event |= CAM_TRIGGER_POINT_EOF;
+		atomic_inc(&link->eof_event_cnt);
+		CAM_DBG(CAM_REQ,
+			"Req_id: %llu, eof_event_cnt: %d, link subscribe event: %d",
+			dev_req->req_id, link->eof_event_cnt,
+			link->subscribe_event);
+	}
+
 	task->process_cb = &cam_req_mgr_process_add_req;
 	rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0);
 	CAM_DBG(CAM_CRM, "X: dev %x dev req %lld",
@@ -2935,6 +3041,12 @@ static int cam_req_mgr_cb_notify_trigger(
 
 	trigger_id = trigger_data->trigger_id;
 
+	if ((!atomic_read(&link->eof_event_cnt)) &&
+		(trigger_data->trigger == CAM_TRIGGER_POINT_EOF)) {
+		CAM_DBG(CAM_CRM, "Not any request to schedule at EOF");
+		goto end;
+	}
+
 	spin_lock_bh(&link->link_state_spin_lock);
 	if (link->state < CAM_CRM_LINK_STATE_READY) {
 		CAM_WARN(CAM_CRM, "invalid link state:%d", link->state);
@@ -2943,7 +3055,8 @@ static int cam_req_mgr_cb_notify_trigger(
 		goto end;
 	}
 
-	if ((link->watchdog) && (link->watchdog->pause_timer))
+	if ((link->watchdog) && (link->watchdog->pause_timer) &&
+		(trigger_data->trigger == CAM_TRIGGER_POINT_SOF))
 		link->watchdog->pause_timer = false;
 
 	if (link->dual_trigger) {
@@ -2963,7 +3076,9 @@ static int cam_req_mgr_cb_notify_trigger(
 		}
 	}
 
-	crm_timer_reset(link->watchdog);
+	if (trigger_data->trigger == CAM_TRIGGER_POINT_SOF)
+		crm_timer_reset(link->watchdog);
+
 	spin_unlock_bh(&link->link_state_spin_lock);
 
 	task = cam_req_mgr_workq_get_task(link->workq);
@@ -2974,7 +3089,8 @@ static int cam_req_mgr_cb_notify_trigger(
 		goto end;
 	}
 	task_data = (struct crm_task_payload *)task->payload;
-	task_data->type = CRM_WORKQ_TASK_NOTIFY_SOF;
+	task_data->type = (trigger_data->trigger == CAM_TRIGGER_POINT_SOF) ?
+		CRM_WORKQ_TASK_NOTIFY_SOF : CRM_WORKQ_TASK_NOTIFY_EOF;
 	notify_trigger = (struct cam_req_mgr_trigger_notify *)&task_data->u;
 	notify_trigger->frame_id = trigger_data->frame_id;
 	notify_trigger->link_hdl = trigger_data->link_hdl;
@@ -3022,8 +3138,7 @@ static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link,
 		if (link_info->u.link_info_v1.num_devices >
 			CAM_REQ_MGR_MAX_HANDLES)
 			return -EPERM;
-	}
-	else if (link_info->version == VERSION_2) {
+	} else if (link_info->version == VERSION_2) {
 		if (link_info->u.link_info_v2.num_devices >
 			CAM_REQ_MGR_MAX_HANDLES_V2)
 			return -EPERM;

+ 28 - 12
drivers/cam_req_mgr/cam_req_mgr_core.h

@@ -49,6 +49,7 @@ enum crm_workq_task_type {
 	CRM_WORKQ_TASK_DEV_ADD_REQ,
 	CRM_WORKQ_TASK_APPLY_REQ,
 	CRM_WORKQ_TASK_NOTIFY_SOF,
+	CRM_WORKQ_TASK_NOTIFY_EOF,
 	CRM_WORKQ_TASK_NOTIFY_ERR,
 	CRM_WORKQ_TASK_NOTIFY_FREEZE,
 	CRM_WORKQ_TASK_SCHED_REQ,
@@ -178,25 +179,39 @@ struct cam_req_mgr_apply {
 	int32_t skip_idx;
 };
 
+/**
+ * struct crm_tbl_slot_special_ops
+ * @dev_hdl         : Device handle who requested for special ops
+ * @apply_at_eof    : Boolean Identifier for request to be applied at EOF
+ * @skip_next_frame : Flag to drop the frame after skip_before_apply frame
+ * @is_applied      : Flag to identify if request is already applied to device
+ *                    in previous frame
+ */
+struct crm_tbl_slot_special_ops {
+	int32_t dev_hdl;
+	bool apply_at_eof;
+	bool skip_next_frame;
+	bool is_applied;
+};
+
 /**
  * struct cam_req_mgr_tbl_slot
  * @idx             : slot index
  * @req_ready_map   : mask tracking which all devices have request ready
  * @state           : state machine for life cycle of a slot
  * @inject_delay    : insert extra bubbling for flash type of use cases
- * @dev_hdl         : stores the dev_hdl, who is having higher inject delay
- * @skip_next_frame : flag to drop the frame after skip_before_apply frame
- * @is_applied      : flag to identify if request is already applied to
- *                    device.
+ * @ops             : special operation for the table slot
+ *                    e.g.
+ *                    skip_next frame: in case of applying one device
+ *                    and skip others
+ *                    apply_at_eof: device that needs to apply at EOF
  */
 struct cam_req_mgr_tbl_slot {
-	int32_t             idx;
-	uint32_t            req_ready_map;
-	enum crm_req_state  state;
-	uint32_t            inject_delay;
-	int32_t             dev_hdl;
-	bool                skip_next_frame;
-	bool                is_applied;
+	int32_t                                idx;
+	uint32_t                               req_ready_map;
+	enum crm_req_state                     state;
+	uint32_t                               inject_delay;
+	struct  crm_tbl_slot_special_ops       ops;
 };
 
 /**
@@ -348,6 +363,7 @@ struct cam_req_mgr_connected_device {
  * @dual_trigger         : Links needs to wait for two triggers prior to
  *                         applying the settings
  * @trigger_cnt          : trigger count value per device initiating the trigger
+ * @eof_event_cnt        : Atomic variable to track the number of EOF requests
  */
 struct cam_req_mgr_core_link {
 	int32_t                              link_hdl;
@@ -380,7 +396,7 @@ struct cam_req_mgr_core_link {
 	uint64_t                             prev_sof_timestamp;
 	bool                                 dual_trigger;
 	uint32_t    trigger_cnt[CAM_REQ_MGR_MAX_TRIGGERS];
-
+	atomic_t                             eof_event_cnt;
 };
 
 /**

+ 13 - 10
drivers/cam_req_mgr/cam_req_mgr_interface.h

@@ -186,12 +186,13 @@ 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_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_MAX             : invalid event type
  */
 enum cam_req_mgr_link_evt_type {
 	CAM_REQ_MGR_LINK_EVT_ERR,
@@ -261,12 +262,15 @@ struct cam_req_mgr_error_notify {
  * @req_id               : req id which device is ready to process
  * @skip_before_applying : before applying req mgr introduce bubble
  *                         by not sending request to devices. ex: IFE and Flash
+ * @trigger_eof          : to identify that one of the device at this slot needs
+ *                         to be apply at EOF
  */
 struct cam_req_mgr_add_request {
 	int32_t  link_hdl;
 	int32_t  dev_hdl;
 	uint64_t req_id;
 	uint32_t skip_before_applying;
+	bool     trigger_eof;
 };
 
 
@@ -355,15 +359,14 @@ struct cam_req_mgr_flush_request {
 
 /**
  * struct cam_req_mgr_event_data
- * @link_hdl : link handle
- * @req_id   : request id
- * @evt_type : link event
+ * @link_hdl          : link handle
+ * @req_id            : request id
+ * @evt_type          : link event
  */
 struct cam_req_mgr_link_evt_data {
 	int32_t  link_hdl;
 	int32_t  dev_hdl;
 	uint64_t req_id;
-
 	enum cam_req_mgr_link_evt_type evt_type;
 	union {
 		enum cam_req_mgr_device_error error;

+ 1 - 0
drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c

@@ -370,6 +370,7 @@ static void cam_actuator_update_req_mgr(
 	add_req.req_id = csl_packet->header.request_id;
 	add_req.dev_hdl = a_ctrl->bridge_intf.device_hdl;
 	add_req.skip_before_applying = 0;
+	add_req.trigger_eof = false;
 
 	if (a_ctrl->bridge_intf.crm_cb &&
 		a_ctrl->bridge_intf.crm_cb->add_req) {

+ 98 - 7
drivers/cam_sensor_module/cam_flash/cam_flash_core.c

@@ -11,6 +11,9 @@
 #include "cam_common_util.h"
 #include "cam_packet_util.h"
 
+static uint default_on_timer = 2;
+module_param(default_on_timer, uint, 0644);
+
 int cam_flash_led_prepare(struct led_trigger *trigger, int options,
 	int *max_current, bool is_wled)
 {
@@ -396,7 +399,8 @@ static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl,
 			cam_res_mgr_led_trigger_event(
 				flash_ctrl->torch_trigger[i], curr);
 		}
-	} else if (op == CAMERA_SENSOR_FLASH_OP_FIREHIGH) {
+	} else if ((op == CAMERA_SENSOR_FLASH_OP_FIREHIGH) ||
+		(op == CAMERA_SENSOR_FLASH_OP_FIREDURATION)) {
 		for (i = 0; i < flash_ctrl->flash_num_sources; i++) {
 			if (flash_ctrl->flash_trigger[i]) {
 				max_current = soc_private->flash_max_current[i];
@@ -416,10 +420,39 @@ static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl,
 		return -EINVAL;
 	}
 
-	if (flash_ctrl->switch_trigger)
+	if (flash_ctrl->switch_trigger) {
+#if IS_ENABLED(CONFIG_LEDS_QTI_FLASH)
+		int rc = 0;
+
+		if (op == CAMERA_SENSOR_FLASH_OP_FIREDURATION) {
+			struct flash_led_param param;
+
+			param.off_time_ms =
+				flash_data->flash_active_time_ms;
+			/* This is to dynamically change the turn on time */
+			param.on_time_ms = default_on_timer;
+			CAM_DBG(CAM_FLASH,
+				"Precise flash_on time: %u, Precise flash_off time: %u",
+				param.on_time_ms, param.off_time_ms);
+			rc = qti_flash_led_set_param(
+				flash_ctrl->switch_trigger,
+				param);
+			if (rc) {
+				CAM_ERR(CAM_FLASH,
+					"LED set param fail rc= %d", rc);
+				return rc;
+			}
+		}
+#else
+		if (op == CAMERA_SENSOR_FLASH_OP_FIREDURATION) {
+			CAM_ERR(CAM_FLASH, "FIREDURATION op not supported");
+			return -EINVAL;
+		}
+#endif
 		cam_res_mgr_led_trigger_event(
 			flash_ctrl->switch_trigger,
 			(enum led_brightness)LED_SWITCH_ON);
+	}
 
 	return 0;
 }
@@ -489,6 +522,30 @@ static int cam_flash_high(
 	return rc;
 }
 
+static int cam_flash_duration(struct cam_flash_ctrl *fctrl,
+	struct cam_flash_frame_setting *flash_data)
+{
+	int i = 0, rc = 0;
+
+	if (!flash_data) {
+		CAM_ERR(CAM_FLASH, "Flash Data NULL");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < fctrl->torch_num_sources; i++)
+		if (fctrl->torch_trigger[i])
+			cam_res_mgr_led_trigger_event(
+				fctrl->torch_trigger[i],
+				LED_OFF);
+
+	rc = cam_flash_ops(fctrl, flash_data,
+		CAMERA_SENSOR_FLASH_OP_FIREDURATION);
+	if (rc)
+		CAM_ERR(CAM_FLASH, "Fire PreciseFlash Failed: %d", rc);
+
+	return rc;
+}
+
 static int cam_flash_i2c_delete_req(struct cam_flash_ctrl *fctrl,
 	uint64_t req_id)
 {
@@ -850,6 +907,19 @@ int cam_flash_pmic_apply_setting(struct cam_flash_ctrl *fctrl,
 					"Flash off failed %d", rc);
 				goto apply_setting_err;
 			}
+		} else if ((flash_data->opcode ==
+			CAMERA_SENSOR_FLASH_OP_FIREDURATION) &&
+			(flash_data->cmn_attr.is_settings_valid) &&
+			(flash_data->cmn_attr.request_id == req_id)) {
+			if (fctrl->flash_state == CAM_FLASH_STATE_START) {
+				rc = cam_flash_duration(fctrl, flash_data);
+				if (rc) {
+					CAM_ERR(CAM_FLASH,
+						"PreciaseFlash op failed:%d",
+						rc);
+					goto apply_setting_err;
+				}
+			}
 		} else if (flash_data->opcode == CAM_PKT_NOP_OPCODE) {
 			CAM_DBG(CAM_FLASH, "NOP Packet");
 		} else {
@@ -1473,6 +1543,18 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
 
 			if (flash_data->opcode == CAMERA_SENSOR_FLASH_OP_OFF)
 				add_req.skip_before_applying |= SKIP_NEXT_FRAME;
+
+			if (flash_data->opcode ==
+				CAMERA_SENSOR_FLASH_OP_FIREDURATION) {
+				add_req.trigger_eof = true;
+				/* Active time for the preflash */
+				flash_data->flash_active_time_ms =
+				(flash_operation_info->time_on_duration_ns)
+					/ 1000000;
+				CAM_DBG(CAM_FLASH,
+					"PRECISE FLASH: active_time: %llu",
+					flash_data->flash_active_time_ms);
+			}
 		}
 		break;
 		default:
@@ -1660,15 +1742,24 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg)
 		add_req.dev_hdl = fctrl->bridge_intf.device_hdl;
 
 		if ((csl_packet->header.op_code & 0xFFFFF) ==
-			CAM_FLASH_PACKET_OPCODE_SET_OPS)
-			add_req.skip_before_applying |= 1;
-		else
+			CAM_FLASH_PACKET_OPCODE_SET_OPS) {
+			if ((flash_data->opcode !=
+				CAMERA_SENSOR_FLASH_OP_FIREDURATION))
+				add_req.skip_before_applying |= 1;
+			else if (flash_data->opcode ==
+				CAMERA_SENSOR_FLASH_OP_FIREDURATION)
+				add_req.trigger_eof = true;
+			else
+				add_req.skip_before_applying = 0;
+		} else {
 			add_req.skip_before_applying = 0;
-
+		}
+		CAM_DBG(CAM_FLASH,
+			"add req to req_mgr= %lld:: trigger_eof: %d",
+			add_req.req_id, add_req.trigger_eof);
 		if (fctrl->bridge_intf.crm_cb &&
 			fctrl->bridge_intf.crm_cb->add_req)
 			fctrl->bridge_intf.crm_cb->add_req(&add_req);
-		CAM_DBG(CAM_FLASH, "add req to req_mgr= %lld", add_req.req_id);
 	}
 
 	return rc;

+ 8 - 7
drivers/cam_sensor_module/cam_flash/cam_flash_dev.h

@@ -108,13 +108,13 @@ struct cam_flash_init_packet {
 
 /**
  * struct flash_frame_setting
- * @cmn_attr         : Provides common attributes
- * @num_iterations   : Iterations used to perform RER
- * @led_on_delay_ms  : LED on time in milisec
- * @led_off_delay_ms : LED off time in milisec
- * @opcode           : Command buffer opcode
- * @led_current_ma[] : LED current array in miliamps
- *
+ * @cmn_attr             : Provides common attributes
+ * @num_iterations       : Iterations used to perform RER
+ * @led_on_delay_ms      : LED on time in milisec
+ * @led_off_delay_ms     : LED off time in milisec
+ * @opcode               : Command buffer opcode
+ * @led_current_ma[]     : LED current array in miliamps
+ * @flash_active_time_ms : Flash_On time with precise flash
  */
 struct cam_flash_frame_setting {
 	struct cam_flash_common_attr cmn_attr;
@@ -123,6 +123,7 @@ struct cam_flash_frame_setting {
 	uint16_t                     led_off_delay_ms;
 	int8_t                       opcode;
 	uint32_t                     led_current_ma[CAM_FLASH_MAX_LED_TRIGGERS];
+	uint64_t                     flash_active_time_ms;
 };
 
 /**

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

@@ -25,6 +25,7 @@ static void cam_sensor_update_req_mgr(
 		csl_packet->header.request_id);
 	add_req.dev_hdl = s_ctrl->bridge_intf.device_hdl;
 	add_req.skip_before_applying = 0;
+	add_req.trigger_eof = false;
 	if (s_ctrl->bridge_intf.crm_cb &&
 		s_ctrl->bridge_intf.crm_cb->add_req)
 		s_ctrl->bridge_intf.crm_cb->add_req(&add_req);

+ 1 - 0
drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h

@@ -77,6 +77,7 @@ enum camera_flash_opcode {
 	CAMERA_SENSOR_FLASH_OP_OFF,
 	CAMERA_SENSOR_FLASH_OP_FIRELOW,
 	CAMERA_SENSOR_FLASH_OP_FIREHIGH,
+	CAMERA_SENSOR_FLASH_OP_FIREDURATION,
 	CAMERA_SENSOR_FLASH_OP_MAX,
 };