msm: camera: isp: Add support for dynamically loadable VFE driver

Implement the remove driver functions for ISP HW drivers. This enables
the dynamic loadable capability to the ISP driver.

Change-Id: I99f70bf8cb57fccbb2b495622752d1f0983580e8
Signed-off-by: Harsh Shah <harshs@codeaurora.org>
Signed-off-by: Soundrapandian Jeyaprakash <jsoundra@codeaurora.org>
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
index c4fae99..9203ee6 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
@@ -838,15 +838,13 @@
 	struct cam_vfe_bus_ver2_hw_info *ver2_hw_info,
 	struct cam_isp_resource_node    *wm_res)
 {
-	int rc = 0;
 	struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data;
 
 	rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver2_wm_resource_data),
 		GFP_KERNEL);
 	if (!rsrc_data) {
-		CDBG("Failed to alloc for wm res priv\n");
-		rc = -ENOMEM;
-		return rc;
+		CDBG("Failed to alloc for WM res priv\n");
+		return -ENOMEM;
 	}
 	wm_res->res_priv = rsrc_data;
 
@@ -863,7 +861,32 @@
 	wm_res->bottom_half_handler = cam_vfe_bus_handle_wm_done_bottom_half;
 	wm_res->hw_intf = ver2_bus_priv->common_data.hw_intf;
 
-	return rc;
+	return 0;
+}
+
+static int cam_vfe_bus_deinit_wm_resource(
+	struct cam_isp_resource_node    *wm_res)
+{
+	struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data;
+
+	wm_res->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE;
+	INIT_LIST_HEAD(&wm_res->list);
+
+	wm_res->start = NULL;
+	wm_res->stop = NULL;
+	wm_res->top_half_handler = NULL;
+	wm_res->bottom_half_handler = NULL;
+	wm_res->hw_intf = NULL;
+
+	rsrc_data = wm_res->res_priv;
+	wm_res->res_priv = NULL;
+	if (!rsrc_data) {
+		pr_err("Error! WM res priv is NULL\n");
+		return -ENOMEM;
+	}
+	kfree(rsrc_data);
+
+	return 0;
 }
 
 static void cam_vfe_bus_add_wm_to_comp_grp(
@@ -1212,8 +1235,7 @@
 	struct cam_vfe_bus_ver2_hw_info *ver2_hw_info,
 	struct cam_isp_resource_node    *comp_grp)
 {
-	struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data =
-		comp_grp->res_priv;
+	struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = NULL;
 
 	rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver2_comp_grp_data),
 		GFP_KERNEL);
@@ -1231,7 +1253,6 @@
 	rsrc_data->hw_regs         = &ver2_hw_info->comp_grp_reg[index];
 	rsrc_data->dual_slave_core = CAM_VFE_BUS_VER2_VFE_CORE_MAX;
 
-
 	if (rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 &&
 		rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5)
 		list_add_tail(&comp_grp->list,
@@ -1250,6 +1271,32 @@
 	return 0;
 }
 
+static int cam_vfe_bus_deinit_comp_grp(
+	struct cam_isp_resource_node    *comp_grp)
+{
+	struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data =
+		comp_grp->res_priv;
+
+	comp_grp->start = NULL;
+	comp_grp->stop = NULL;
+	comp_grp->top_half_handler = NULL;
+	comp_grp->bottom_half_handler = NULL;
+	comp_grp->hw_intf = NULL;
+
+	list_del_init(&comp_grp->list);
+	comp_grp->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE;
+
+	comp_grp->res_priv = NULL;
+
+	if (!rsrc_data) {
+		pr_err("Error! comp_grp_priv is NULL\n");
+		return -ENODEV;
+	}
+	kfree(rsrc_data);
+
+	return 0;
+}
+
 static int cam_vfe_bus_acquire_vfe_out(void *bus_priv, void *acquire_args)
 {
 	int                                     rc = -ENODEV;
@@ -1533,6 +1580,30 @@
 	return 0;
 }
 
+static int cam_vfe_bus_deinit_vfe_out_resource(
+	struct cam_isp_resource_node    *vfe_out)
+{
+	struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = vfe_out->res_priv;
+
+	vfe_out->start = NULL;
+	vfe_out->stop = NULL;
+	vfe_out->top_half_handler = NULL;
+	vfe_out->bottom_half_handler = NULL;
+	vfe_out->hw_intf = NULL;
+
+	vfe_out->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE;
+	INIT_LIST_HEAD(&vfe_out->list);
+	vfe_out->res_priv = NULL;
+
+	if (!rsrc_data) {
+		pr_err("Error! vfe out priv is NULL\n");
+		return -ENOMEM;
+	}
+	kfree(rsrc_data);
+
+	return 0;
+}
+
 static int cam_vfe_bus_get_evt_payload(
 	struct cam_vfe_bus_ver2_priv         *bus_priv,
 	struct cam_vfe_bus_irq_evt_payload  **evt_payload)
@@ -1923,7 +1994,7 @@
 	if (!vfe_bus_local) {
 		CDBG("Failed to alloc for vfe_bus\n");
 		rc = -ENOMEM;
-		goto err_alloc_bus;
+		goto end;
 	}
 
 	bus_priv = kzalloc(sizeof(struct cam_vfe_bus_ver2_priv),
@@ -1931,7 +2002,7 @@
 	if (!bus_priv) {
 		CDBG("Failed to alloc for vfe_bus_priv\n");
 		rc = -ENOMEM;
-		goto err_alloc_priv;
+		goto free_bus_local;
 	}
 	vfe_bus_local->bus_priv = bus_priv;
 
@@ -1948,8 +2019,8 @@
 		rc = cam_vfe_bus_init_wm_resource(i, bus_priv, bus_hw_info,
 			&bus_priv->bus_client[i]);
 		if (rc < 0) {
-			pr_err("Error! Init WM failed\n");
-			goto err_init_wm;
+			pr_err("Error! Init WM failed rc=%d\n", rc);
+			goto deinit_wm;
 		}
 	}
 
@@ -1957,8 +2028,8 @@
 		rc = cam_vfe_bus_init_comp_grp(i, bus_priv, bus_hw_info,
 			&bus_priv->comp_grp[i]);
 		if (rc < 0) {
-			pr_err("Error! Init Comp Grp failed\n");
-			goto err_init_comp_grp;
+			pr_err("Error! Init Comp Grp failed rc=%d\n", rc);
+			goto deinit_comp_grp;
 		}
 	}
 
@@ -1966,8 +2037,8 @@
 		rc = cam_vfe_bus_init_vfe_out_resource(i, bus_priv, bus_hw_info,
 			&bus_priv->vfe_out[i]);
 		if (rc < 0) {
-			pr_err("Error! Init VFE Out failed\n");
-			goto err_init_vfe_out;
+			pr_err("Error! Init VFE Out failed rc=%d\n", rc);
+			goto deinit_vfe_out;
 		}
 	}
 
@@ -1988,14 +2059,89 @@
 
 	*vfe_bus = vfe_bus_local;
 
+	CDBG("Exit\n");
 	return rc;
 
-err_init_vfe_out:
-err_init_comp_grp:
-err_init_wm:
+deinit_vfe_out:
+	if (i < 0)
+		i = CAM_VFE_BUS_VER2_VFE_OUT_MAX;
+	for (--i; i >= 0; i--)
+		cam_vfe_bus_deinit_vfe_out_resource(&bus_priv->vfe_out[i]);
+
+deinit_comp_grp:
+	if (i < 0)
+		i = CAM_VFE_BUS_VER2_COMP_GRP_MAX;
+	for (--i; i >= 0; i--)
+		cam_vfe_bus_deinit_comp_grp(&bus_priv->comp_grp[i]);
+
+deinit_wm:
+	if (i < 0)
+		i = CAM_VFE_BUS_VER2_MAX_CLIENTS;
+	for (--i; i >= 0; i--)
+		cam_vfe_bus_deinit_wm_resource(&bus_priv->bus_client[i]);
+
 	kfree(vfe_bus_local->bus_priv);
-err_alloc_priv:
+
+free_bus_local:
 	kfree(vfe_bus_local);
-err_alloc_bus:
+
+end:
 	return rc;
 }
+
+int cam_vfe_bus_ver2_deinit(
+	struct cam_vfe_bus                  **vfe_bus)
+{
+	int i, rc = 0;
+	struct cam_vfe_bus_ver2_priv    *bus_priv = NULL;
+	struct cam_vfe_bus              *vfe_bus_local;
+
+	if (!vfe_bus || !*vfe_bus) {
+		pr_err("Error! Invalid input\n");
+		return -EINVAL;
+	}
+	vfe_bus_local = *vfe_bus;
+
+	bus_priv = vfe_bus_local->bus_priv;
+	if (!bus_priv) {
+		pr_err("Error! bus_priv is NULL\n");
+		rc = -ENODEV;
+		goto free_bus_local;
+	}
+
+	INIT_LIST_HEAD(&bus_priv->free_payload_list);
+	for (i = 0; i < 128; i++)
+		INIT_LIST_HEAD(&bus_priv->evt_payload[i].list);
+
+	for (i = 0; i < CAM_VFE_BUS_VER2_MAX_CLIENTS; i++) {
+		rc = cam_vfe_bus_deinit_wm_resource(&bus_priv->bus_client[i]);
+		if (rc < 0)
+			pr_err("Error! Deinit WM failed rc=%d\n", rc);
+	}
+
+	for (i = 0; i < CAM_VFE_BUS_VER2_COMP_GRP_MAX; i++) {
+		rc = cam_vfe_bus_deinit_comp_grp(&bus_priv->comp_grp[i]);
+		if (rc < 0)
+			pr_err("Error! Deinit Comp Grp failed rc=%d\n", rc);
+	}
+
+	for (i = 0; i < CAM_VFE_BUS_VER2_VFE_OUT_MAX; i++) {
+		rc = cam_vfe_bus_deinit_vfe_out_resource(&bus_priv->vfe_out[i]);
+		if (rc < 0)
+			pr_err("Error! Deinit VFE Out failed rc=%d\n", rc);
+	}
+
+	INIT_LIST_HEAD(&bus_priv->free_comp_grp);
+	INIT_LIST_HEAD(&bus_priv->free_dual_comp_grp);
+	INIT_LIST_HEAD(&bus_priv->used_comp_grp);
+
+	kfree(vfe_bus_local->bus_priv);
+
+free_bus_local:
+	kfree(vfe_bus_local);
+
+	*vfe_bus = NULL;
+
+	return rc;
+}
+