Selaa lähdekoodia

msm: camera: utils: Add camera clk wrapper infrastructure

Source clocks that are shared with multiple devices need
to be consolidated before setting clock rate on them.
If not, a set call with lower freq from one device
overwrites the frequency that previously set by another
device, causing issues. Clk wrapper helps to consolidate
the frequency among multiple devices and set the max
frequency required by all of them. A shared clock notation
is defined in DT and go through clk wrapper based on that.

CRs-Fixed: 2901925
Change-Id: Ia5b2b5fd3c0619c994e27d96fad6e11d126de182
Signed-off-by: Pavan Kumar Chilamkurthi <[email protected]>
Pavan Kumar Chilamkurthi 4 vuotta sitten
vanhempi
sitoutus
cd745eb39a

+ 3 - 6
drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c

@@ -76,8 +76,7 @@ static int cam_csid_ppi_enable_hw(struct cam_csid_ppi_hw  *ppi_hw)
 	}
 
 	for (i = 0; i < soc_info->num_clk; i++) {
-		rc = cam_soc_util_clk_enable(soc_info->clk[i],
-			soc_info->clk_name[i], 0, NULL);
+		rc = cam_soc_util_clk_enable(soc_info, false, i, -1, NULL);
 		if (rc)
 			goto clk_disable;
 	}
@@ -107,8 +106,7 @@ static int cam_csid_ppi_enable_hw(struct cam_csid_ppi_hw  *ppi_hw)
 	return 0;
 clk_disable:
 	for (--i; i >= 0; i--)
-		cam_soc_util_clk_disable(soc_info->clk[i],
-			soc_info->clk_name[i]);
+		cam_soc_util_clk_disable(soc_info, false, i);
 	ppi_hw->hw_info->open_count--;
 	return rc;
 }
@@ -154,8 +152,7 @@ static int cam_csid_ppi_disable_hw(struct cam_csid_ppi_hw *ppi_hw)
 	ppi_hw->device_enabled = 0;
 
 	for (i = 0; i < soc_info->num_clk; i++)
-		cam_soc_util_clk_disable(soc_info->clk[i],
-			soc_info->clk_name[i]);
+		cam_soc_util_clk_disable(soc_info, false, i);
 
 	return rc;
 }

+ 13 - 11
drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.c

@@ -64,9 +64,8 @@ int cam_tfe_init_soc_resources(struct cam_hw_soc_info *soc_info,
 
 clk_option:
 
-	rc = cam_soc_util_get_option_clk_by_name(soc_info,
-		CAM_TFE_DSP_CLK_NAME, &soc_private->dsp_clk,
-		&soc_private->dsp_clk_index, &soc_private->dsp_clk_rate);
+	rc = cam_soc_util_get_option_clk_by_name(soc_info, CAM_TFE_DSP_CLK_NAME,
+		&soc_private->dsp_clk_index);
 	if (rc)
 		CAM_WARN(CAM_ISP, "Option clk get failed with rc %d", rc);
 
@@ -129,10 +128,13 @@ int cam_tfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info)
 			"Error! Release platform resource failed rc=%d", rc);
 
 
-	rc = cam_soc_util_clk_put(&soc_private->dsp_clk);
-	if (rc < 0)
-		CAM_ERR(CAM_ISP,
-			"Error Put dsp clk failed rc=%d", rc);
+	if (soc_private->dsp_clk_index != -1) {
+		rc = cam_soc_util_put_optional_clk(soc_info,
+			soc_private->dsp_clk_index);
+		if (rc)
+			CAM_ERR(CAM_ISP,
+				"Error Put dsp clk failed rc=%d", rc);
+	}
 
 	kfree(soc_private);
 
@@ -198,8 +200,8 @@ int cam_tfe_soc_enable_clk(struct cam_hw_soc_info *soc_info,
 	soc_private = soc_info->soc_private;
 
 	if (strcmp(clk_name, CAM_TFE_DSP_CLK_NAME) == 0) {
-		rc = cam_soc_util_clk_enable(soc_private->dsp_clk,
-			CAM_TFE_DSP_CLK_NAME, soc_private->dsp_clk_rate, NULL);
+		rc = cam_soc_util_clk_enable(soc_info, true,
+			soc_private->dsp_clk_index, 0, NULL);
 		if (rc)
 			CAM_ERR(CAM_ISP,
 			"Error enable dsp clk failed rc=%d", rc);
@@ -222,8 +224,8 @@ int cam_tfe_soc_disable_clk(struct cam_hw_soc_info *soc_info,
 	soc_private = soc_info->soc_private;
 
 	if (strcmp(clk_name, CAM_TFE_DSP_CLK_NAME) == 0) {
-		rc = cam_soc_util_clk_disable(soc_private->dsp_clk,
-			CAM_TFE_DSP_CLK_NAME);
+		rc = cam_soc_util_clk_disable(soc_info, true,
+			soc_private->dsp_clk_index);
 		if (rc)
 			CAM_ERR(CAM_ISP,
 			"Error enable dsp clk failed rc=%d", rc);

+ 2 - 3
drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _CAM_TFE_SOC_H_
@@ -26,15 +26,14 @@ enum cam_cpas_handle_id {
  *                           This handle is used for all further interface
  *                           with CPAS.
  * @cpas_version:            Has cpas version read from Hardware
+ * @dsp_clk_index:           DSP clk index in optional clocks
  * @num_pid:                 number of pids of tfe
  * @pid:                     TFE pid value list
  */
 struct cam_tfe_soc_private {
 	uint32_t    cpas_handle;
 	uint32_t    cpas_version;
-	struct clk *dsp_clk;
 	int32_t     dsp_clk_index;
-	int32_t     dsp_clk_rate;
 	uint32_t    num_pid;
 	uint32_t    pid[CAM_ISP_HW_MAX_PID_VAL];
 };

+ 9 - 9
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c

@@ -158,9 +158,8 @@ int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info,
 		goto free_soc_private;
 	}
 
-	rc = cam_soc_util_get_option_clk_by_name(soc_info,
-		CAM_VFE_DSP_CLK_NAME, &soc_private->dsp_clk,
-		&soc_private->dsp_clk_index, &soc_private->dsp_clk_rate);
+	rc = cam_soc_util_get_option_clk_by_name(soc_info, CAM_VFE_DSP_CLK_NAME,
+		&soc_private->dsp_clk_index);
 	if (rc)
 		CAM_DBG(CAM_ISP, "Option clk get failed with rc %d", rc);
 
@@ -222,8 +221,9 @@ int cam_vfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info)
 			"Error! Release platform resources failed rc=%d", rc);
 
 	if (soc_private->dsp_clk_index != -1) {
-		rc = cam_soc_util_clk_put(&soc_private->dsp_clk);
-		if (rc < 0)
+		rc = cam_soc_util_put_optional_clk(soc_info,
+			soc_private->dsp_clk_index);
+		if (rc)
 			CAM_ERR(CAM_ISP,
 				"Error Put dsp clk failed rc=%d", rc);
 	}
@@ -306,8 +306,8 @@ int cam_vfe_soc_enable_clk(struct cam_hw_soc_info *soc_info,
 			goto end;
 		}
 
-		rc = cam_soc_util_clk_enable(soc_private->dsp_clk,
-			CAM_VFE_DSP_CLK_NAME, soc_private->dsp_clk_rate, NULL);
+		rc = cam_soc_util_clk_enable(soc_info, true,
+			soc_private->dsp_clk_index, 0, NULL);
 		if (rc)
 			CAM_ERR(CAM_ISP,
 			"Error enable dsp clk failed rc=%d", rc);
@@ -338,8 +338,8 @@ int cam_vfe_soc_disable_clk(struct cam_hw_soc_info *soc_info,
 			goto end;
 		}
 
-		rc = cam_soc_util_clk_disable(soc_private->dsp_clk,
-			CAM_VFE_DSP_CLK_NAME);
+		rc = cam_soc_util_clk_disable(soc_info, true,
+			soc_private->dsp_clk_index);
 		if (rc)
 			CAM_ERR(CAM_ISP,
 			"Error disable dsp clk failed rc=%d", rc);

+ 2 - 3
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _CAM_VFE_SOC_H_
@@ -22,6 +22,7 @@
  *                           This handle is used for all further interface
  *                           with CPAS.
  * @cpas_version:            Has cpas version read from Hardware
+ * @dsp_clk_index:           DSP clk index in optional clocks
  * @ubwc_static_ctrl:        UBWC static control configuration
  * @is_ife_lite:             Flag to indicate full vs lite IFE
  * @ife_clk_src:             IFE source clock
@@ -31,9 +32,7 @@
 struct cam_vfe_soc_private {
 	uint32_t    cpas_handle;
 	uint32_t    cpas_version;
-	struct clk *dsp_clk;
 	int32_t     dsp_clk_index;
-	int32_t     dsp_clk_rate;
 	uint32_t    ubwc_static_ctrl[UBWC_STATIC_CONFIG_MAX];
 	bool        is_ife_lite;
 	uint64_t    ife_clk_src;

+ 8 - 9
drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c

@@ -2096,12 +2096,13 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl,
 					power_setting->config_val;
 
 			for (j = 0; j < soc_info->num_clk; j++) {
-				rc = cam_soc_util_clk_enable(soc_info->clk[j],
-					soc_info->clk_name[j],
-					soc_info->clk_rate[0][j],
-					NULL);
-				if (rc)
+				rc = cam_soc_util_clk_enable(soc_info, false,
+					i, 0, NULL);
+				if (rc) {
+					CAM_ERR(CAM_UTIL,
+						"Failed in clk enable %d", i);
 					break;
+				}
 			}
 
 			if (rc < 0) {
@@ -2224,8 +2225,7 @@ power_up_failed:
 		switch (power_setting->seq_type) {
 		case SENSOR_MCLK:
 			for (i = soc_info->num_clk - 1; i >= 0; i--) {
-				cam_soc_util_clk_disable(soc_info->clk[i],
-					soc_info->clk_name[i]);
+				cam_soc_util_clk_disable(soc_info, false, i);
 			}
 			ret = cam_config_mclk_reg(ctrl, soc_info, index);
 			if (ret < 0) {
@@ -2384,8 +2384,7 @@ int cam_sensor_util_power_down(struct cam_sensor_power_ctrl_t *ctrl,
 		switch (pd->seq_type) {
 		case SENSOR_MCLK:
 			for (i = soc_info->num_clk - 1; i >= 0; i--) {
-				cam_soc_util_clk_disable(soc_info->clk[i],
-					soc_info->clk_name[i]);
+				cam_soc_util_clk_disable(soc_info, false, i);
 			}
 
 			ret = cam_config_mclk_reg(ctrl, soc_info, index);

+ 523 - 50
drivers/cam_utils/cam_soc_util.c

@@ -13,8 +13,274 @@
 #include "cam_cx_ipeak.h"
 #include "cam_mem_mgr.h"
 
+#define CAM_TO_MASK(bitn)          (1 << (int)(bitn))
+#define CAM_IS_BIT_SET(mask, bit)  ((mask) & CAM_TO_MASK(bit))
+#define CAM_SET_BIT(mask, bit)     ((mask) |= CAM_TO_MASK(bit))
+#define CAM_CLEAR_BIT(mask, bit)   ((mask) &= ~CAM_TO_MASK(bit))
+
+/**
+ * struct cam_clk_wrapper_clk: This represents an entry corresponding to a
+ *                             shared clock in Clk wrapper. Clients that share
+ *                             the same clock are registered to this clk entry
+ *                             and set rate from them is consolidated before
+ *                             setting it to clk driver.
+ *
+ * @list:           List pointer to point to next shared clk entry
+ * @clk_id:         Clk Id of this clock
+ * @curr_clk_rate:  Current clock rate set for this clock
+ * @client_list:    List of clients registered to this shared clock entry
+ * @num_clients:    Number of clients
+ **/
+struct cam_clk_wrapper_clk {
+	struct list_head list;
+	uint32_t clk_id;
+	int64_t curr_clk_rate;
+	struct list_head client_list;
+	uint32_t num_clients;
+};
+
+/**
+ * struct cam_clk_wrapper_client: This represents a client (device) that wants
+ *                                to share the clock with some other client.
+ *
+ * @list:           List pointer to point to next client that share the
+ *                  same clock
+ * @soc_info:       soc_info of client. This is used as unique identifier
+ *                  for a client
+ * @clk:            Clk handle
+ * @curr_clk_rate:  Current clock rate set for this client
+ **/
+struct cam_clk_wrapper_client {
+	struct list_head list;
+	struct cam_hw_soc_info *soc_info;
+	struct clk *clk;
+	int64_t curr_clk_rate;
+};
+
 static char supported_clk_info[256];
 
+static DEFINE_MUTEX(wrapper_lock);
+static LIST_HEAD(wrapper_clk_list);
+
+static int cam_soc_util_clk_wrapper_register_entry(
+	uint32_t clk_id, struct clk *clk, struct cam_hw_soc_info *soc_info,
+	const char *clk_name)
+{
+	struct cam_clk_wrapper_clk *wrapper_clk;
+	struct cam_clk_wrapper_client *wrapper_client;
+	bool clock_found = false;
+	int rc = 0;
+
+	mutex_lock(&wrapper_lock);
+
+	list_for_each_entry(wrapper_clk, &wrapper_clk_list, list) {
+		CAM_DBG(CAM_UTIL, "Clk list id %d num clients %d",
+			wrapper_clk->clk_id, wrapper_clk->num_clients);
+
+		if (wrapper_clk->clk_id == clk_id) {
+			clock_found = true;
+			list_for_each_entry(wrapper_client,
+				&wrapper_clk->client_list, list) {
+				CAM_DBG(CAM_UTIL,
+					"Clk id %d entry client %s",
+					wrapper_clk->clk_id,
+					wrapper_client->soc_info->dev_name);
+				if (wrapper_client->soc_info == soc_info) {
+					CAM_ERR(CAM_UTIL,
+						"Register with same soc info, clk id %d, client %s",
+						clk_id, soc_info->dev_name);
+					rc = -EINVAL;
+					goto end;
+				}
+			}
+			break;
+		}
+	}
+
+	if (!clock_found) {
+		CAM_DBG(CAM_UTIL, "Adding new entry for clk id %d", clk_id);
+		wrapper_clk = kzalloc(sizeof(struct cam_clk_wrapper_clk),
+			GFP_KERNEL);
+		if (!wrapper_clk) {
+			CAM_ERR(CAM_UTIL,
+				"Failed in allocating new clk entry %d",
+				clk_id);
+			rc = -ENOMEM;
+			goto end;
+		}
+
+		wrapper_clk->clk_id = clk_id;
+		INIT_LIST_HEAD(&wrapper_clk->list);
+		INIT_LIST_HEAD(&wrapper_clk->client_list);
+		list_add_tail(&wrapper_clk->list, &wrapper_clk_list);
+	}
+	wrapper_client = kzalloc(sizeof(struct cam_clk_wrapper_client),
+		GFP_KERNEL);
+	if (!wrapper_client) {
+		CAM_ERR(CAM_UTIL, "Failed in allocating new client entry %d",
+			clk_id);
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	wrapper_client->soc_info = soc_info;
+	wrapper_client->clk = clk;
+
+	INIT_LIST_HEAD(&wrapper_client->list);
+	list_add_tail(&wrapper_client->list, &wrapper_clk->client_list);
+	wrapper_clk->num_clients++;
+
+	CAM_DBG(CAM_UTIL,
+		"Adding new client %s for clk[%s] id %d, num clients %d",
+		soc_info->dev_name, clk_name, clk_id, wrapper_clk->num_clients);
+end:
+	mutex_unlock(&wrapper_lock);
+	return rc;
+}
+
+static int cam_soc_util_clk_wrapper_unregister_entry(
+	uint32_t clk_id, struct cam_hw_soc_info *soc_info)
+{
+	struct cam_clk_wrapper_clk *wrapper_clk;
+	struct cam_clk_wrapper_client *wrapper_client;
+	bool clock_found = false;
+	bool client_found = false;
+	int rc = 0;
+
+	mutex_lock(&wrapper_lock);
+
+	list_for_each_entry(wrapper_clk, &wrapper_clk_list, list) {
+		CAM_DBG(CAM_UTIL, "Clk list id %d num clients %d",
+			wrapper_clk->clk_id, wrapper_clk->num_clients);
+
+		if (wrapper_clk->clk_id == clk_id) {
+			clock_found = true;
+			list_for_each_entry(wrapper_client,
+				&wrapper_clk->client_list, list) {
+				CAM_DBG(CAM_UTIL, "Clk id %d entry client %s",
+					wrapper_clk->clk_id,
+					wrapper_client->soc_info->dev_name);
+				if (wrapper_client->soc_info == soc_info) {
+					client_found = true;
+					wrapper_clk->num_clients--;
+					list_del_init(&wrapper_client->list);
+					kfree(wrapper_client);
+					break;
+				}
+			}
+			break;
+		}
+	}
+
+	if (!clock_found) {
+		CAM_ERR(CAM_UTIL, "Shared clk id %d entry not found", clk_id);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	if (!client_found) {
+		CAM_ERR(CAM_UTIL,
+			"Client %pK for Shared clk id %d entry not found",
+			soc_info, clk_id);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	CAM_DBG(CAM_UTIL, "Unregister client %s for clk id %d, num clients %d",
+		soc_info->dev_name, clk_id, wrapper_clk->num_clients);
+
+	if (!wrapper_clk->num_clients) {
+		list_del_init(&wrapper_clk->list);
+		kfree(wrapper_clk);
+	}
+end:
+	mutex_unlock(&wrapper_lock);
+	return rc;
+}
+
+static int cam_soc_util_clk_wrapper_set_clk_rate(
+	uint32_t clk_id, struct cam_hw_soc_info *soc_info,
+	struct clk *clk, int64_t clk_rate)
+{
+	struct cam_clk_wrapper_clk *wrapper_clk;
+	struct cam_clk_wrapper_client *wrapper_client;
+	bool clk_found = false;
+	bool client_found = false;
+	int rc = 0;
+	int64_t final_clk_rate = 0;
+
+	if (!soc_info || !clk) {
+		CAM_ERR(CAM_UTIL, "Invalid param soc_info %pK clk %pK",
+			soc_info, clk);
+		return -EINVAL;
+	}
+
+	mutex_lock(&wrapper_lock);
+
+	list_for_each_entry(wrapper_clk, &wrapper_clk_list, list) {
+		CAM_DBG(CAM_UTIL, "Clk list id %d num clients %d",
+			wrapper_clk->clk_id, wrapper_clk->num_clients);
+		if (wrapper_clk->clk_id == clk_id) {
+			clk_found = true;
+			break;
+		}
+	}
+
+	if (!clk_found) {
+		CAM_ERR(CAM_UTIL, "Clk entry not found id %d client %s",
+			clk_id, soc_info->dev_name);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	list_for_each_entry(wrapper_client, &wrapper_clk->client_list, list) {
+		CAM_DBG(CAM_UTIL, "Clk id %d client %s, clk rate %lld",
+			wrapper_clk->clk_id, wrapper_client->soc_info->dev_name,
+			wrapper_client->curr_clk_rate);
+		if (wrapper_client->soc_info == soc_info) {
+			client_found = true;
+			CAM_DBG(CAM_UTIL,
+				"Clk enable clk id %d, client %s curr %ld new %ld",
+				clk_id, wrapper_client->soc_info->dev_name,
+				wrapper_client->curr_clk_rate, clk_rate);
+
+			wrapper_client->curr_clk_rate = clk_rate;
+		}
+
+		if (final_clk_rate < wrapper_client->curr_clk_rate)
+			final_clk_rate = wrapper_client->curr_clk_rate;
+	}
+
+	if (!client_found) {
+		CAM_ERR(CAM_UTIL,
+			"Wrapper clk enable without client entry clk id %d client %s",
+			clk_id, soc_info->dev_name);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	CAM_DBG(CAM_UTIL,
+		"Clk id %d, client %s, clients rate %ld, curr %ld final %ld",
+		wrapper_clk->clk_id, soc_info->dev_name, clk_rate,
+		wrapper_clk->curr_clk_rate, final_clk_rate);
+
+	if (final_clk_rate != wrapper_clk->curr_clk_rate) {
+		if (final_clk_rate) {
+			rc = clk_set_rate(clk, final_clk_rate);
+			if (rc) {
+				CAM_ERR(CAM_UTIL, "set_rate failed on clk %d",
+					wrapper_clk->clk_id);
+				goto end;
+			}
+		}
+		wrapper_clk->curr_clk_rate = final_clk_rate;
+	}
+
+end:
+	mutex_unlock(&wrapper_lock);
+	return rc;
+}
+
 int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info,
 	int64_t clk_rate, int clk_idx, int32_t *clk_lvl)
 {
@@ -366,18 +632,26 @@ long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info,
  * @clk:              Clock structure information for which rate is to be set
  * @clk_name:         Name of the clock for which rate is being set
  * @clk_rate:         Clock rate to be set
+ * @shared_clk:       Whether this is a shared clk
+ * @clk_id:           Clock ID
  * @applied_clk_rate: Final clock rate set to the clk
  *
  * @return:         Success or failure
  */
-static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name,
-	int64_t clk_rate, unsigned long *applied_clk_rate)
+static int cam_soc_util_set_clk_rate(struct cam_hw_soc_info *soc_info,
+	struct clk *clk, const char *clk_name,
+	int64_t clk_rate, bool shared_clk, uint32_t clk_id,
+	unsigned long *applied_clk_rate)
 {
 	int rc = 0;
 	long clk_rate_round = -1;
+	bool set_rate = false;
 
-	if (!clk || !clk_name)
+	if (!clk || !clk_name) {
+		CAM_ERR(CAM_UTIL, "Invalid input clk %pK clk_name %pK",
+			clk, clk_name);
 		return -EINVAL;
+	}
 
 	CAM_DBG(CAM_UTIL, "set %s, rate %lld", clk_name, clk_rate);
 	if (clk_rate > 0) {
@@ -388,11 +662,7 @@ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name,
 				clk_name, clk_rate_round);
 			return clk_rate_round;
 		}
-		rc = clk_set_rate(clk, clk_rate_round);
-		if (rc) {
-			CAM_ERR(CAM_UTIL, "set_rate failed on %s", clk_name);
-			return rc;
-		}
+		set_rate = true;
 	} else if (clk_rate == INIT_RATE) {
 		clk_rate_round = clk_get_rate(clk);
 		CAM_DBG(CAM_UTIL, "init new_rate %ld", clk_rate_round);
@@ -404,10 +674,23 @@ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name,
 				return clk_rate_round;
 			}
 		}
-		rc = clk_set_rate(clk, clk_rate_round);
-		if (rc) {
-			CAM_ERR(CAM_UTIL, "set_rate failed on %s", clk_name);
-			return rc;
+		set_rate = true;
+	}
+
+	if (set_rate) {
+		if (shared_clk) {
+			CAM_DBG(CAM_UTIL,
+				"Dev %s clk %s id %d Set Shared clk %ld",
+				soc_info->dev_name, clk_name, clk_id,
+				clk_rate_round);
+			cam_soc_util_clk_wrapper_set_clk_rate(
+				clk_id, soc_info, clk, clk_rate_round);
+		} else {
+			rc = clk_set_rate(clk, clk_rate_round);
+			if (rc) {
+				CAM_ERR(CAM_UTIL, "set_rate failed on %s", clk_name);
+				return rc;
+			}
 		}
 	}
 
@@ -461,8 +744,10 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info,
 			apply_level);
 	}
 
-	rc = cam_soc_util_set_clk_rate(clk,
+	rc = cam_soc_util_set_clk_rate(soc_info, clk,
 		soc_info->clk_name[src_clk_idx], clk_rate,
+		CAM_IS_BIT_SET(soc_info->shared_clk_mask, src_clk_idx),
+		soc_info->clk_id[src_clk_idx],
 		&soc_info->applied_src_clk_rate);
 	if (rc) {
 		CAM_ERR(CAM_UTIL,
@@ -481,9 +766,11 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info,
 			continue;
 		}
 		clk = soc_info->clk[scl_clk_idx];
-		rc = cam_soc_util_set_clk_rate(clk,
+		rc = cam_soc_util_set_clk_rate(soc_info, clk,
 			soc_info->clk_name[scl_clk_idx],
 			soc_info->clk_rate[apply_level][scl_clk_idx],
+			CAM_IS_BIT_SET(soc_info->shared_clk_mask, scl_clk_idx),
+			soc_info->clk_id[scl_clk_idx],
 			NULL);
 		if (rc) {
 			CAM_WARN(CAM_UTIL,
@@ -497,21 +784,26 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info,
 	return 0;
 }
 
-int cam_soc_util_clk_put(struct clk **clk)
+int cam_soc_util_put_optional_clk(struct cam_hw_soc_info *soc_info,
+	int32_t clk_indx)
 {
-	if (!(*clk)) {
-		CAM_ERR(CAM_UTIL, "Invalid params clk");
+	if (clk_indx < 0) {
+		CAM_ERR(CAM_UTIL, "Invalid params clk %d", clk_indx);
 		return -EINVAL;
 	}
 
-	clk_put(*clk);
-	*clk = NULL;
+	if (CAM_IS_BIT_SET(soc_info->optional_shared_clk_mask, clk_indx))
+		cam_soc_util_clk_wrapper_unregister_entry(
+			soc_info->optional_clk_id[clk_indx], soc_info);
+
+	clk_put(soc_info->optional_clk[clk_indx]);
+	soc_info->optional_clk[clk_indx] = NULL;
 
 	return 0;
 }
 
 static struct clk *cam_soc_util_option_clk_get(struct device_node *np,
-	int index)
+	int index, uint32_t *clk_id)
 {
 	struct of_phandle_args clkspec;
 	struct clk *clk;
@@ -526,23 +818,25 @@ static struct clk *cam_soc_util_option_clk_get(struct device_node *np,
 		return ERR_PTR(rc);
 
 	clk = of_clk_get_from_provider(&clkspec);
+
+	*clk_id = clkspec.args[0];
 	of_node_put(clkspec.np);
 
 	return clk;
 }
 
 int cam_soc_util_get_option_clk_by_name(struct cam_hw_soc_info *soc_info,
-	const char *clk_name, struct clk **clk, int32_t *clk_index,
-	int32_t *clk_rate)
+	const char *clk_name, int32_t *clk_index)
 {
 	int index = 0;
 	int rc = 0;
 	struct device_node *of_node = NULL;
+	uint32_t shared_clk_val;
 
-	if (!soc_info || !clk_name || !clk) {
+	if (!soc_info || !clk_name || !clk_index) {
 		CAM_ERR(CAM_UTIL,
-			"Invalid params soc_info %pK clk_name %s clk %pK",
-			soc_info, clk_name, clk);
+			"Invalid params soc_info %pK clk_name %s clk_index %pK",
+			soc_info, clk_name, clk_index);
 		return -EINVAL;
 	}
 
@@ -553,52 +847,129 @@ int cam_soc_util_get_option_clk_by_name(struct cam_hw_soc_info *soc_info,
 	if (index < 0) {
 		CAM_DBG(CAM_UTIL, "No clk data for %s", clk_name);
 		*clk_index = -1;
-		*clk = ERR_PTR(-EINVAL);
 		return -EINVAL;
 	}
 
-	*clk = cam_soc_util_option_clk_get(of_node, index);
-	if (IS_ERR(*clk)) {
+	if (index >= CAM_SOC_MAX_OPT_CLK) {
+		CAM_ERR(CAM_UTIL, "Insufficient optional clk entries %d %d",
+			index, CAM_SOC_MAX_OPT_CLK);
+		return -EINVAL;
+	}
+
+	of_property_read_string_index(of_node, "clock-names-option",
+		index, &(soc_info->optional_clk_name[index]));
+
+	soc_info->optional_clk[index] = cam_soc_util_option_clk_get(of_node,
+		index, &soc_info->optional_clk_id[index]);
+	if (IS_ERR(soc_info->optional_clk[index])) {
 		CAM_ERR(CAM_UTIL, "No clk named %s found. Dev %s", clk_name,
 			soc_info->dev_name);
 		*clk_index = -1;
-		*clk = NULL;
 		return -EFAULT;
 	}
 	*clk_index = index;
 
 	rc = of_property_read_u32_index(of_node, "clock-rates-option",
-		index, clk_rate);
+		index, &soc_info->optional_clk_rate[index]);
 	if (rc) {
 		CAM_ERR(CAM_UTIL,
 			"Error reading clock-rates clk_name %s index %d",
 			clk_name, index);
-		cam_soc_util_clk_put(clk);
-		*clk_rate = 0;
-		return rc;
+		goto error;
 	}
 
 	/*
 	 * Option clocks are assumed to be available to single Device here.
 	 * Hence use INIT_RATE instead of NO_SET_RATE.
 	 */
-	*clk_rate = (*clk_rate == 0) ? (int32_t)INIT_RATE : *clk_rate;
+	soc_info->optional_clk_rate[index] =
+		(soc_info->optional_clk_rate[index] == 0) ?
+		(int32_t)INIT_RATE : soc_info->optional_clk_rate[index];
 
 	CAM_DBG(CAM_UTIL, "clk_name %s index %d clk_rate %d",
-		clk_name, *clk_index, *clk_rate);
+		clk_name, *clk_index, soc_info->optional_clk_rate[index]);
+
+	rc = of_property_read_u32_index(of_node, "shared-clks-option",
+		index, &shared_clk_val);
+	if (rc) {
+		CAM_DBG(CAM_UTIL, "Not shared clk  %s index %d",
+			clk_name, index);
+	} else if (shared_clk_val > 1) {
+		CAM_WARN(CAM_UTIL, "Invalid shared clk val %d", shared_clk_val);
+	} else {
+		CAM_DBG(CAM_UTIL,
+			"Dev %s shared clk  %s index %d, clk id %d, shared_clk_val %d",
+			soc_info->dev_name, clk_name, index,
+			soc_info->optional_clk_id[index], shared_clk_val);
+
+		if (shared_clk_val) {
+			CAM_SET_BIT(soc_info->optional_shared_clk_mask, index);
+
+			/* Create a wrapper entry if this is a shared clock */
+			CAM_DBG(CAM_UTIL,
+				"Dev %s, clk %s, id %d register wrapper entry for shared clk",
+				soc_info->dev_name,
+				soc_info->optional_clk_name[index],
+				soc_info->optional_clk_id[index]);
+
+			rc = cam_soc_util_clk_wrapper_register_entry(
+				soc_info->optional_clk_id[index],
+				soc_info->optional_clk[index], soc_info,
+				soc_info->optional_clk_name[index]);
+			if (rc) {
+				CAM_ERR(CAM_UTIL,
+					"Failed in registering shared clk Dev %s id %d",
+					soc_info->dev_name,
+					soc_info->optional_clk_id[index]);
+				goto error;
+			}
+		}
+	}
 
 	return 0;
+error:
+	clk_put(soc_info->optional_clk[index]);
+	soc_info->optional_clk_rate[index] = 0;
+	soc_info->optional_clk[index] = NULL;
+	*clk_index = -1;
+
+	return rc;
 }
 
-int cam_soc_util_clk_enable(struct clk *clk, const char *clk_name,
-	int32_t clk_rate, unsigned long *applied_clock_rate)
+int cam_soc_util_clk_enable(struct cam_hw_soc_info *soc_info,
+	bool optional_clk, int32_t clk_idx, int32_t apply_level,
+	unsigned long *applied_clock_rate)
 {
 	int rc = 0;
+	struct clk *clk;
+	const char *clk_name;
+	int32_t clk_rate;
+	uint32_t shared_clk_mask;
+	uint32_t clk_id;
 
-	if (!clk || !clk_name)
+	if (!soc_info || (clk_idx < 0) || (apply_level >= CAM_MAX_VOTE)) {
+		CAM_ERR(CAM_UTIL, "Invalid param %d %d", clk_idx, apply_level);
 		return -EINVAL;
+	}
 
-	rc = cam_soc_util_set_clk_rate(clk, clk_name, clk_rate,
+	if (optional_clk) {
+		clk = soc_info->optional_clk[clk_idx];
+		clk_name = soc_info->optional_clk_name[clk_idx];
+		clk_rate = (apply_level == -1) ?
+			0 : soc_info->optional_clk_rate[clk_idx];
+		shared_clk_mask = soc_info->optional_shared_clk_mask;
+		clk_id = soc_info->optional_clk_id[clk_idx];
+	} else {
+		clk = soc_info->clk[clk_idx];
+		clk_name = soc_info->clk_name[clk_idx];
+		clk_rate = (apply_level == -1) ?
+			0 : soc_info->clk_rate[apply_level][clk_idx];
+		shared_clk_mask = soc_info->shared_clk_mask;
+		clk_id = soc_info->clk_id[clk_idx];
+	}
+
+	rc = cam_soc_util_set_clk_rate(soc_info, clk, clk_name, clk_rate,
+		CAM_IS_BIT_SET(shared_clk_mask, clk_idx), clk_id,
 		applied_clock_rate);
 	if (rc)
 		return rc;
@@ -612,14 +983,42 @@ int cam_soc_util_clk_enable(struct clk *clk, const char *clk_name,
 	return rc;
 }
 
-int cam_soc_util_clk_disable(struct clk *clk, const char *clk_name)
+int cam_soc_util_clk_disable(struct cam_hw_soc_info *soc_info,
+	bool optional_clk, int32_t clk_idx)
 {
-	if (!clk || !clk_name)
+
+	struct clk *clk;
+	const char *clk_name;
+	uint32_t shared_clk_mask;
+	uint32_t clk_id;
+
+	if (!soc_info || (clk_idx < 0)) {
+		CAM_ERR(CAM_UTIL, "Invalid param %d", clk_idx);
 		return -EINVAL;
+	}
+
+	if (optional_clk) {
+		clk = soc_info->optional_clk[clk_idx];
+		clk_name = soc_info->optional_clk_name[clk_idx];
+		shared_clk_mask = soc_info->optional_shared_clk_mask;
+		clk_id = soc_info->optional_clk_id[clk_idx];
+	} else {
+		clk = soc_info->clk[clk_idx];
+		clk_name = soc_info->clk_name[clk_idx];
+		shared_clk_mask = soc_info->shared_clk_mask;
+		clk_id = soc_info->clk_id[clk_idx];
+	}
 
 	CAM_DBG(CAM_UTIL, "disable %s", clk_name);
 	clk_disable_unprepare(clk);
 
+	if (CAM_IS_BIT_SET(shared_clk_mask, clk_idx)) {
+		CAM_DBG(CAM_UTIL,
+			"Dev %s clk %s Disabling Shared clk, set 0 rate",
+			soc_info->dev_name, clk_name);
+		cam_soc_util_clk_wrapper_set_clk_rate(clk_id, soc_info, clk, 0);
+	}
+
 	return 0;
 }
 
@@ -657,9 +1056,7 @@ int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info,
 		cam_cx_ipeak_update_vote_cx_ipeak(soc_info, apply_level);
 
 	for (i = 0; i < soc_info->num_clk; i++) {
-		rc = cam_soc_util_clk_enable(soc_info->clk[i],
-			soc_info->clk_name[i],
-			soc_info->clk_rate[apply_level][i],
+		rc = cam_soc_util_clk_enable(soc_info, false, i, apply_level,
 			&applied_clk_rate);
 		if (rc)
 			goto clk_disable;
@@ -683,8 +1080,7 @@ clk_disable:
 	if (soc_info->cam_cx_ipeak_enable)
 		cam_cx_ipeak_update_vote_cx_ipeak(soc_info, 0);
 	for (i--; i >= 0; i--) {
-		cam_soc_util_clk_disable(soc_info->clk[i],
-			soc_info->clk_name[i]);
+		cam_soc_util_clk_disable(soc_info, false, i);
 	}
 
 	return rc;
@@ -710,8 +1106,7 @@ void cam_soc_util_clk_disable_default(struct cam_hw_soc_info *soc_info)
 	if (soc_info->cam_cx_ipeak_enable)
 		cam_cx_ipeak_unvote_cx_ipeak(soc_info);
 	for (i = soc_info->num_clk - 1; i >= 0; i--)
-		cam_soc_util_clk_disable(soc_info->clk[i],
-			soc_info->clk_name[i]);
+		cam_soc_util_clk_disable(soc_info, false, i);
 }
 
 /**
@@ -736,6 +1131,8 @@ static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info)
 	const char *clk_control_debugfs = NULL;
 	const char *clk_cntl_lvl_string = NULL;
 	enum cam_vote_level level;
+	int shared_clk_cnt;
+	struct of_phandle_args clk_args = {0};
 
 	if (!soc_info || !soc_info->dev)
 		return -EINVAL;
@@ -856,8 +1253,54 @@ static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info)
 			soc_info->src_clk_idx = i;
 			CAM_DBG(CAM_UTIL, "src clock = %s, index = %d",
 				src_clk_str, i);
-			break;
 		}
+
+		rc = of_parse_phandle_with_args(of_node, "clocks",
+			"#clock-cells", i, &clk_args);
+		if (rc) {
+			CAM_ERR(CAM_CPAS,
+				"failed to clock info rc=%d", rc);
+			rc = -EINVAL;
+			goto end;
+		}
+
+		soc_info->clk_id[i] = clk_args.args[0];
+		of_node_put(clk_args.np);
+
+		CAM_DBG(CAM_UTIL, "Dev %s clk %s id %d",
+			soc_info->dev_name, soc_info->clk_name[i],
+			soc_info->clk_id[i]);
+	}
+
+	soc_info->shared_clk_mask = 0;
+	shared_clk_cnt = of_property_count_u32_elems(of_node, "shared-clks");
+	if (shared_clk_cnt <= 0) {
+		CAM_DBG(CAM_UTIL, "Dev %s, no shared clks", soc_info->dev_name);
+	} else if (shared_clk_cnt != count) {
+		CAM_ERR(CAM_UTIL, "Dev %s, incorrect shared clock count %d %d",
+			soc_info->dev_name, shared_clk_cnt, count);
+		rc = -EINVAL;
+		goto end;
+	} else {
+		uint32_t shared_clk_val;
+
+		for (i = 0; i < shared_clk_cnt; i++) {
+			rc = of_property_read_u32_index(of_node,
+				"shared-clks", i, &shared_clk_val);
+			if (rc || (shared_clk_val > 1)) {
+				CAM_ERR(CAM_UTIL,
+					"Incorrect shared clk info at %d, val=%d, count=%d",
+					i, shared_clk_val, shared_clk_cnt);
+				rc = -EINVAL;
+				goto end;
+			}
+
+			if (shared_clk_val)
+				CAM_SET_BIT(soc_info->shared_clk_mask, i);
+		}
+
+		CAM_DBG(CAM_UTIL, "Dev %s shared clk mask 0x%x",
+			soc_info->dev_name, soc_info->shared_clk_mask);
 	}
 
 	/* scalable clk info parsing */
@@ -952,9 +1395,11 @@ int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info,
 			soc_info->clk_name[i],
 			soc_info->clk_rate[apply_level][i]);
 
-		rc = cam_soc_util_set_clk_rate(soc_info->clk[i],
+		rc = cam_soc_util_set_clk_rate(soc_info, soc_info->clk[i],
 			soc_info->clk_name[i],
 			soc_info->clk_rate[apply_level][i],
+			CAM_IS_BIT_SET(soc_info->shared_clk_mask, i),
+			soc_info->clk_id[i],
 			&applied_clk_rate);
 		if (rc < 0) {
 			CAM_DBG(CAM_UTIL,
@@ -1633,6 +2078,26 @@ int cam_soc_util_request_platform_resource(
 			rc = -ENOENT;
 			goto put_clk;
 		}
+
+		/* Create a wrapper entry if this is a shared clock */
+		if (CAM_IS_BIT_SET(soc_info->shared_clk_mask, i)) {
+			CAM_DBG(CAM_UTIL,
+				"Dev %s, clk %s, id %d register wrapper entry for shared clk",
+				soc_info->dev_name, soc_info->clk_name[i],
+				soc_info->clk_id[i]);
+			rc = cam_soc_util_clk_wrapper_register_entry(
+				soc_info->clk_id[i], soc_info->clk[i], soc_info,
+				soc_info->clk_name[i]);
+			if (rc) {
+				CAM_ERR(CAM_UTIL,
+					"Failed in registering shared clk Dev %s id %d",
+					soc_info->dev_name,
+					soc_info->clk_id[i]);
+				clk_put(soc_info->clk[i]);
+				soc_info->clk[i] = NULL;
+				goto put_clk;
+			}
+		}
 	}
 
 	rc = cam_soc_util_request_pinctrl(soc_info);
@@ -1655,6 +2120,10 @@ put_clk:
 		i = soc_info->num_clk;
 	for (i = i - 1; i >= 0; i--) {
 		if (soc_info->clk[i]) {
+			if (CAM_IS_BIT_SET(soc_info->shared_clk_mask, i))
+				cam_soc_util_clk_wrapper_unregister_entry(
+					soc_info->clk_id[i], soc_info);
+
 			clk_put(soc_info->clk[i]);
 			soc_info->clk[i] = NULL;
 		}
@@ -1702,6 +2171,10 @@ int cam_soc_util_release_platform_resource(struct cam_hw_soc_info *soc_info)
 	}
 
 	for (i = soc_info->num_clk - 1; i >= 0; i--) {
+		if (CAM_IS_BIT_SET(soc_info->shared_clk_mask, i))
+			cam_soc_util_clk_wrapper_unregister_entry(
+				soc_info->clk_id[i], soc_info);
+
 		clk_put(soc_info->clk[i]);
 		soc_info->clk[i] = NULL;
 	}

+ 47 - 17
drivers/cam_utils/cam_soc_util.h

@@ -36,6 +36,9 @@
 /* maximum number of device clock */
 #define CAM_SOC_MAX_CLK             32
 
+/* maximum number of optional device clock */
+#define CAM_SOC_MAX_OPT_CLK    2
+
 /* DDR device types */
 #define DDR_TYPE_LPDDR4        6
 #define DDR_TYPE_LPDDR4X       7
@@ -155,12 +158,23 @@ struct cam_soc_gpio_data {
  * @clk:                    Array of associated clock resources
  * @clk_rate:               2D array of clock rates representing clock rate
  *                          values at different vote levels
+ * @clk_id                  Clock IDs
+ * @shared_clk_mask         Mask indicating which of the clocks are shared with
+ *                          other devices. Set rate on these clocks needs to go
+ *                          through camera clk wrapper for aggregation.
  * @prev_clk_level          Last vote level
  * @src_clk_idx:            Source clock index that is rate-controllable
+ * @applied_src_clk_rate    Current clock rate of the core source clk
  * @clk_level_valid:        Indicates whether corresponding level is valid
  * @scl_clk_count:          Number of scalable clocks present
  * @scl_clk_idx:            Index of scalable clocks
- * @applied_src_clk_rate    Current clock rate of the core source clk
+ * @optional_clk_name:      Array of clock names
+ * @optional_clk:           Array of associated clock resources
+ * @optional_clk_rate:      Optional clock's clk rate
+ * @optional_clk_id         Clock IDs
+ * @optional_shared_clk_mask Mask indicating which of the clocks are shared with
+ *                           other devices. Set rate on these clocks needs to go
+ *                           through camera clk wrapper for aggregation.
  * @gpio_data:              Pointer to gpio info
  * @pinctrl_info:           Pointer to pinctrl info
  * @dentry:                 Debugfs entry
@@ -205,12 +219,19 @@ struct cam_hw_soc_info {
 	const char                     *clk_name[CAM_SOC_MAX_CLK];
 	struct clk                     *clk[CAM_SOC_MAX_CLK];
 	int32_t                         clk_rate[CAM_MAX_VOTE][CAM_SOC_MAX_CLK];
+	uint32_t                        clk_id[CAM_SOC_MAX_CLK];
+	uint32_t                        shared_clk_mask;
 	int32_t                         prev_clk_level;
 	int32_t                         src_clk_idx;
 	unsigned long                   applied_src_clk_rate;
 	bool                            clk_level_valid[CAM_MAX_VOTE];
 	int32_t                         scl_clk_count;
 	int32_t                         scl_clk_idx[CAM_SOC_MAX_CLK];
+	const char                     *optional_clk_name[CAM_SOC_MAX_OPT_CLK];
+	struct clk                     *optional_clk[CAM_SOC_MAX_OPT_CLK];
+	int32_t                         optional_clk_rate[CAM_SOC_MAX_OPT_CLK];
+	uint32_t                        optional_clk_id[CAM_SOC_MAX_OPT_CLK];
+	uint32_t                        optional_shared_clk_mask;
 
 	struct cam_soc_gpio_data       *gpio_data;
 	struct cam_soc_pinctrl_info     pinctrl_info;
@@ -427,42 +448,48 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info,
  *
  * @soc_info:           Device soc information
  * @clk_name:           Name of clock to find reference for
- * @clk:                Clock reference pointer to be filled if Success
  * @clk_index:          Clk index in the option clk array to be returned
- * @clk_rate:           Clk rate in the option clk array
  *
  * @return:             0: Success
  *                      Negative: Failure
  */
 int cam_soc_util_get_option_clk_by_name(struct cam_hw_soc_info *soc_info,
-	const char *clk_name, struct clk **clk, int32_t *clk_index,
-	int32_t *clk_rate);
+	const char *clk_name, int32_t *clk_index);
 
 /**
- * cam_soc_util_clk_put()
+ * cam_soc_util_put_optional_clk()
  *
- * @brief:              Put clock specified in params
+ * @brief:              Put clock corresponding to index specified in params
  *
- * @clk:                Reference to the Clock that needs to be put
+ * @soc_info:           Device soc information
+ * @clk_idx:            Clock index in optional clocks to put
  *
  * @return:             Success or failure
  */
-int cam_soc_util_clk_put(struct clk **clk);
+int cam_soc_util_put_optional_clk(struct cam_hw_soc_info *soc_info,
+	int32_t clk_idx);
 
 /**
  * cam_soc_util_clk_enable()
  *
  * @brief:              Enable clock specified in params
  *
- * @clk:                Clock that needs to be turned ON
- * @clk_name:           Clocks name associated with clk
- * @clk_rate:           Clocks rate associated with clk
+ * @soc_info:           Device soc information
+ * @optional_clk:       Whether to set optional clk or normal clk with
+ *                      the idx given
+ * @clk_idx:            Clock index to set
+ * @apply_level:        Apply level.
+ *                      -1 for 0 rate
+ *                      any other value indicate level for normal clocks
+ *                      For optional clocks any other value means the rate saved
+ *                      in soc_info
  * @applied_clock_rate  Final Clock rate applied to the clk
  *
  * @return:             Success or failure
  */
-int cam_soc_util_clk_enable(struct clk *clk, const char *clk_name,
-	int32_t clk_rate, unsigned long *applied_clock_rate);
+int cam_soc_util_clk_enable(struct cam_hw_soc_info *soc_info,
+	bool optional_clk, int32_t clk_idx, int32_t apply_level,
+	unsigned long *applied_clock_rate);
 
 /**
  * cam_soc_util_set_clk_rate_level()
@@ -485,12 +512,15 @@ int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info,
  *
  * @brief:              Disable clock specified in params
  *
- * @clk:                Clock that needs to be turned OFF
- * @clk_name:           Clocks name associated with clk
+ * @soc_info:           Device soc information
+ * @optional_clk:       Whether to set optional clk or normal clk with
+ *                      the idx given
+ * @clk_idx:            Clock index to disable
  *
  * @return:             Success or failure
  */
-int cam_soc_util_clk_disable(struct clk *clk, const char *clk_name);
+int cam_soc_util_clk_disable(struct cam_hw_soc_info *soc_info,
+	bool optional_clk, int32_t clk_idx);
 
 /**
  * cam_soc_util_irq_enable()