Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 85d6d6ae authored by Jeyaprakash Soundrapandian's avatar Jeyaprakash Soundrapandian Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: camera: util: Add support for GPIOs, Pinctrl, Regulators" into dev/msm-4.9-camx

parents ff7b0f70 5852cbf9
Loading
Loading
Loading
Loading
+535 −39
Original line number Diff line number Diff line
@@ -14,6 +14,9 @@

#include <linux/of.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include "cam_soc_util.h"

#undef CDBG
@@ -443,43 +446,304 @@ int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info,
	return rc;
};

int cam_soc_util_get_dt_properties(struct cam_hw_soc_info *soc_info)
static int cam_soc_util_get_dt_gpio_req_tbl(struct device_node *of_node,
	struct cam_soc_gpio_data *gconf, uint16_t *gpio_array,
	uint16_t gpio_array_size)
{
	int32_t rc = 0, i = 0;
	uint32_t count = 0;
	uint32_t *val_array = NULL;

	if (!of_get_property(of_node, "gpio-req-tbl-num", &count))
		return 0;

	count /= sizeof(uint32_t);
	if (!count) {
		pr_err("gpio-req-tbl-num 0\n");
		return 0;
	}

	val_array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL);
	if (!val_array)
		return -ENOMEM;

	gconf->cam_gpio_req_tbl = kcalloc(count, sizeof(struct gpio),
		GFP_KERNEL);
	if (!gconf->cam_gpio_req_tbl) {
		rc = -ENOMEM;
		goto free_val_array;
	}
	gconf->cam_gpio_req_tbl_size = count;

	rc = of_property_read_u32_array(of_node, "gpio-req-tbl-num",
		val_array, count);
	if (rc) {
		pr_err("failed in reading gpio-req-tbl-num, rc = %d\n", rc);
		goto free_gpio_req_tbl;
	}

	for (i = 0; i < count; i++) {
		if (val_array[i] >= gpio_array_size) {
			pr_err("gpio req tbl index %d invalid\n", val_array[i]);
			goto free_gpio_req_tbl;
		}
		gconf->cam_gpio_req_tbl[i].gpio = gpio_array[val_array[i]];
		CDBG("cam_gpio_req_tbl[%d].gpio = %d\n", i,
			gconf->cam_gpio_req_tbl[i].gpio);
	}

	rc = of_property_read_u32_array(of_node, "gpio-req-tbl-flags",
		val_array, count);
	if (rc) {
		pr_err("Failed in gpio-req-tbl-flags, rc %d\n", rc);
		goto free_gpio_req_tbl;
	}

	for (i = 0; i < count; i++) {
		gconf->cam_gpio_req_tbl[i].flags = val_array[i];
		CDBG("cam_gpio_req_tbl[%d].flags = %ld\n", i,
			gconf->cam_gpio_req_tbl[i].flags);
	}

	for (i = 0; i < count; i++) {
		rc = of_property_read_string_index(of_node,
			"gpio-req-tbl-label", i,
			&gconf->cam_gpio_req_tbl[i].label);
		if (rc) {
			pr_err("Failed rc %d\n", rc);
			goto free_gpio_req_tbl;
		}
		CDBG("cam_gpio_req_tbl[%d].label = %s\n", i,
			gconf->cam_gpio_req_tbl[i].label);
	}

	kfree(val_array);

	return rc;

free_gpio_req_tbl:
	kfree(gconf->cam_gpio_req_tbl);
free_val_array:
	kfree(val_array);
	gconf->cam_gpio_req_tbl_size = 0;

	return rc;
}

static int cam_soc_util_get_gpio_info(struct cam_hw_soc_info *soc_info)
{
	int32_t rc = 0, i = 0;
	uint16_t *gpio_array = NULL;
	int16_t gpio_array_size = 0;
	struct cam_soc_gpio_data *gconf = NULL;
	struct device_node *of_node = NULL;
	int count = 0, i = 0, rc = 0;
	struct platform_device *pdev = NULL;

	if (!soc_info || !soc_info->pdev)
		return -EINVAL;

	pdev = soc_info->pdev;

	of_node = pdev->dev.of_node;

	rc = of_property_read_u32(of_node, "cell-index", &soc_info->index);
	/* Validate input parameters */
	if (!of_node) {
		pr_err("Invalid param of_node\n");
		return -EINVAL;
	}

	gpio_array_size = of_gpio_count(of_node);

	if (gpio_array_size <= 0)
		return 0;

	CDBG("gpio count %d\n", gpio_array_size);

	gpio_array = kcalloc(gpio_array_size, sizeof(uint16_t), GFP_KERNEL);
	if (!gpio_array)
		goto free_gpio_conf;

	for (i = 0; i < gpio_array_size; i++) {
		gpio_array[i] = of_get_gpio(of_node, i);
		CDBG("gpio_array[%d] = %d", i, gpio_array[i]);
	}

	gconf = kzalloc(sizeof(*gconf), GFP_KERNEL);
	if (!gconf)
		return -ENOMEM;

	rc = cam_soc_util_get_dt_gpio_req_tbl(of_node, gconf, gpio_array,
		gpio_array_size);
	if (rc) {
		pr_err("device %s failed to read cell-index\n", pdev->name);
		pr_err("failed in msm_camera_get_dt_gpio_req_tbl\n");
		goto free_gpio_array;
	}

	gconf->cam_gpio_common_tbl = kcalloc(gpio_array_size,
				sizeof(struct gpio), GFP_KERNEL);
	if (!gconf->cam_gpio_common_tbl) {
		rc = -ENOMEM;
		goto free_gpio_array;
	}

	for (i = 0; i <= gpio_array_size; i++)
		gconf->cam_gpio_common_tbl[i].gpio = gpio_array[i];

	gconf->cam_gpio_common_tbl_size = gpio_array_size;
	soc_info->gpio_data = gconf;
	kfree(gpio_array);

	return rc;

free_gpio_array:
	kfree(gpio_array);
free_gpio_conf:
	kfree(gconf);
	soc_info->gpio_data = NULL;

	return rc;
}

static int cam_soc_util_request_gpio_table(
	struct cam_hw_soc_info *soc_info, bool gpio_en)
{
	int rc = 0, i = 0;
	uint8_t size = 0;
	struct cam_soc_gpio_data *gpio_conf =
			soc_info->gpio_data;
	struct gpio *gpio_tbl = NULL;


	if (!gpio_conf) {
		CDBG("No GPIO entry\n");
		return 0;
	}
	if (gpio_conf->cam_gpio_common_tbl_size <= 0) {
		pr_err("GPIO table size is invalid\n");
		return -EINVAL;
	}
	size = gpio_conf->cam_gpio_req_tbl_size;
	gpio_tbl = gpio_conf->cam_gpio_req_tbl;

	if (!gpio_tbl || !size) {
		pr_err("Invalid gpio_tbl %pK / size %d\n",
			gpio_tbl, size);
		return -EINVAL;
	}
	for (i = 0; i < size; i++) {
		CDBG("i=%d, gpio=%d dir=%ld\n", i,
			gpio_tbl[i].gpio, gpio_tbl[i].flags);
	}
	if (gpio_en) {
		for (i = 0; i < size; i++) {
			rc = gpio_request_one(gpio_tbl[i].gpio,
				gpio_tbl[i].flags, gpio_tbl[i].label);
			if (rc) {
				/*
				 * After GPIO request fails, contine to
				 * apply new gpios, outout a error message
				 * for driver bringup debug
				 */
				pr_err("gpio %d:%s request fails\n",
					gpio_tbl[i].gpio, gpio_tbl[i].label);
			}
		}
	} else {
		gpio_free_array(gpio_tbl, size);
	}

	return rc;
}

static int cam_soc_util_get_dt_regulator_info
	(struct cam_hw_soc_info *soc_info)
{
	int rc = 0, count = 0, i = 0;
	struct device_node *of_node = NULL;
	struct platform_device *pdev = NULL;

	if (!soc_info || !soc_info->pdev) {
		pr_err("Invalid parameters\n");
		return -EINVAL;
	}

	pdev = soc_info->pdev;
	of_node = pdev->dev.of_node;

	soc_info->num_rgltr = 0;
	count = of_property_count_strings(of_node, "regulator-names");
	if (count != -EINVAL) {
		if (count <= 0) {
			pr_err("no regulators found\n");
			count = 0;
			return -EINVAL;
		}

		soc_info->num_rgltr = count;

	} else {
		CDBG("No regulators node found\n");
		return 0;
	}

	for (i = 0; i < soc_info->num_rgltr; i++) {
		rc = of_property_read_string_index(of_node,
			"regulator-names", i, &soc_info->rgltr_name[i]);
		CDBG("rgltr_name[%d] = %s\n", i, soc_info->rgltr_name[i]);
		if (rc) {
			pr_err("no regulator resource at cnt=%d\n", i);
			rc = -ENODEV;
			return rc;
			return -ENODEV;
		}
	}

	if (!of_property_read_bool(of_node, "rgltr-cntrl-support")) {
		CDBG("No regulator control parameter defined\n");
		soc_info->rgltr_ctrl_support = false;
		return 0;
	}

	soc_info->rgltr_ctrl_support = true;

	rc = of_property_read_u32_array(of_node, "rgltr-min-voltage",
		soc_info->rgltr_min_volt, soc_info->num_rgltr);
	if (rc) {
		pr_err("No minimum volatage value found, rc=%d\n", rc);
		return -EINVAL;
	}

	rc = of_property_read_u32_array(of_node, "rgltr-max-voltage",
		soc_info->rgltr_max_volt, soc_info->num_rgltr);
	if (rc) {
		pr_err("No maximum volatage value found, rc=%d\n", rc);
		return -EINVAL;
	}

	rc = of_property_read_u32_array(of_node, "rgltr-load-current",
		soc_info->rgltr_op_mode, soc_info->num_rgltr);
	if (rc) {
		pr_err("No Load curent found rc=%d\n", rc);
		return -EINVAL;
	}

	return rc;
}

int cam_soc_util_get_dt_properties(struct cam_hw_soc_info *soc_info)
{
	struct device_node *of_node = NULL;
	int count = 0, i = 0, rc = 0;
	struct platform_device *pdev = NULL;

	if (!soc_info || !soc_info->pdev)
		return -EINVAL;

	pdev = soc_info->pdev;
	of_node = pdev->dev.of_node;

	rc = of_property_read_u32(of_node, "cell-index", &soc_info->index);
	if (rc) {
		pr_err("device %s failed to read cell-index\n", pdev->name);
		return rc;
	}
	count = of_property_count_strings(of_node, "reg-names");
	if (count <= 0) {
		pr_err("no reg-names found\n");
@@ -519,6 +783,7 @@ int cam_soc_util_get_dt_properties(struct cam_hw_soc_info *soc_info)
		&soc_info->irq_name);
	if (rc) {
		pr_warn("No interrupt line present\n");
		rc = 0;
	} else {
		soc_info->irq_line = platform_get_resource_byname(pdev,
			IORESOURCE_IRQ, soc_info->irq_name);
@@ -529,7 +794,17 @@ int cam_soc_util_get_dt_properties(struct cam_hw_soc_info *soc_info)
		}
	}

	rc = cam_soc_util_get_dt_regulator_info(soc_info);
	if (rc)
		return rc;

	rc = cam_soc_util_get_dt_clk_info(soc_info);
	if (rc)
		return rc;

	rc = cam_soc_util_get_gpio_info(soc_info);
	if (rc)
		return rc;

	return rc;
}
@@ -559,18 +834,207 @@ static int cam_soc_util_get_regulator(struct platform_device *pdev,
	return rc;
}

int cam_soc_util_request_platform_resource(struct cam_hw_soc_info *soc_info,
int cam_soc_util_regulator_disable(struct regulator *rgltr,
	const char *rgltr_name, uint32_t rgltr_min_volt,
	uint32_t rgltr_max_volt, uint32_t rgltr_op_mode,
	uint32_t rgltr_delay_ms)
{
	int32_t rc = 0;

	if (!rgltr) {
		pr_err("Invalid NULL parameter\n");
		return -EINVAL;
	}

	rc = regulator_disable(rgltr);
	if (rc) {
		pr_err("%s regulator disable failed\n", rgltr_name);
		return rc;
	}

	if (rgltr_delay_ms > 20)
		msleep(rgltr_delay_ms);
	else if (rgltr_delay_ms)
		usleep_range(rgltr_delay_ms * 1000,
			(rgltr_delay_ms * 1000) + 1000);

	if (regulator_count_voltages(rgltr) > 0) {
		regulator_set_load(rgltr, 0);
		regulator_set_voltage(rgltr, 0, rgltr_max_volt);
	}

	return rc;
}


int cam_soc_util_regulator_enable(struct regulator *rgltr,
	const char *rgltr_name,
	uint32_t rgltr_min_volt, uint32_t rgltr_max_volt,
	uint32_t rgltr_op_mode, uint32_t rgltr_delay)
{
	int32_t rc = 0;

	if (!rgltr) {
		pr_err("Invalid NULL parameter\n");
		return -EINVAL;
	}

	if (regulator_count_voltages(rgltr) > 0) {
		CDBG("voltage min=%d, max=%d\n",
			rgltr_min_volt, rgltr_max_volt);

		rc = regulator_set_voltage(
			rgltr, rgltr_min_volt, rgltr_max_volt);
		if (rc) {
			pr_err("%s set voltage failed\n", rgltr_name);
			return rc;
		}

		rc = regulator_set_load(rgltr, rgltr_op_mode);
		if (rc) {
			pr_err("%s set optimum mode failed\n", rgltr_name);
			return rc;
		}
	}

	rc = regulator_enable(rgltr);
	if (rc) {
		pr_err("%s regulator_enable failed\n", rgltr_name);
		return rc;
	}

	if (rgltr_delay > 20)
		msleep(rgltr_delay);
	else if (rgltr_delay)
		usleep_range(rgltr_delay * 1000,
			(rgltr_delay * 1000) + 1000);

	return rc;
}

static int cam_soc_util_request_pinctrl(
	struct cam_hw_soc_info *soc_info) {

	struct cam_soc_pinctrl_info *device_pctrl = &soc_info->pinctrl_info;
	struct device *dev = &soc_info->pdev->dev;

	device_pctrl->pinctrl = devm_pinctrl_get(dev);
	if (IS_ERR_OR_NULL(device_pctrl->pinctrl)) {
		CDBG("Pinctrl not available\n");
		device_pctrl->pinctrl = NULL;
		return 0;
	}
	device_pctrl->gpio_state_active =
		pinctrl_lookup_state(device_pctrl->pinctrl,
				CAM_SOC_PINCTRL_STATE_DEFAULT);
	if (IS_ERR_OR_NULL(device_pctrl->gpio_state_active)) {
		pr_err("Failed to get the active state pinctrl handle\n");
		device_pctrl->gpio_state_active = NULL;
		return -EINVAL;
	}
	device_pctrl->gpio_state_suspend
		= pinctrl_lookup_state(device_pctrl->pinctrl,
				CAM_SOC_PINCTRL_STATE_SLEEP);
	if (IS_ERR_OR_NULL(device_pctrl->gpio_state_suspend)) {
		pr_err("Failed to get the suspend state pinctrl handle\n");
		device_pctrl->gpio_state_suspend = NULL;
		return -EINVAL;
	}
	return 0;
}

static void cam_soc_util_regulator_disable_default(
	struct cam_hw_soc_info *soc_info)
{
	int j = 0;
	uint32_t num_rgltr = soc_info->num_rgltr;

	for (j = num_rgltr-1; j >= 0; j--) {
		if (soc_info->rgltr_ctrl_support == true) {
			cam_soc_util_regulator_disable(soc_info->rgltr[j],
				soc_info->rgltr_name[j],
				soc_info->rgltr_min_volt[j],
				soc_info->rgltr_max_volt[j],
				soc_info->rgltr_op_mode[j],
				soc_info->rgltr_delay[j]);
		} else {
			if (soc_info->rgltr[j])
				regulator_disable(soc_info->rgltr[j]);
		}
	}
}

static int cam_soc_util_regulator_enable_default(
	struct cam_hw_soc_info *soc_info)
{
	int j = 0, rc = 0;
	uint32_t num_rgltr = soc_info->num_rgltr;

	for (j = 0; j < num_rgltr; j++) {
		if (soc_info->rgltr_ctrl_support == true) {
			rc = cam_soc_util_regulator_enable(soc_info->rgltr[j],
				soc_info->rgltr_name[j],
				soc_info->rgltr_min_volt[j],
				soc_info->rgltr_max_volt[j],
				soc_info->rgltr_op_mode[j],
				soc_info->rgltr_delay[j]);
		} else {
			if (soc_info->rgltr[j])
				rc = regulator_enable(soc_info->rgltr[j]);
		}

		if (rc) {
			pr_err("%s enable failed\n", soc_info->rgltr_name[j]);
			goto disable_rgltr;
		}
	}

	return rc;
disable_rgltr:

	for (j--; j >= 0; j--) {
		if (soc_info->rgltr_ctrl_support == true) {
			cam_soc_util_regulator_disable(soc_info->rgltr[j],
				soc_info->rgltr_name[j],
				soc_info->rgltr_min_volt[j],
				soc_info->rgltr_max_volt[j],
				soc_info->rgltr_op_mode[j],
				soc_info->rgltr_delay[j]);
		} else {
			if (soc_info->rgltr[j])
				regulator_disable(soc_info->rgltr[j]);
		}
	}

	return rc;
}

int cam_soc_util_request_platform_resource(
	struct cam_hw_soc_info *soc_info,
	irq_handler_t handler, void *irq_data)
{
	int i = 0, rc = 0;
	struct platform_device *pdev = NULL;

	if (!soc_info || !soc_info->pdev)

	if (!soc_info || !soc_info->pdev) {
		pr_err("Invalid parameters\n");
		return -EINVAL;
	}

	pdev = soc_info->pdev;

	for (i = 0; i < soc_info->num_mem_block; i++) {
		if (soc_info->reserve_mem) {
			if (!request_mem_region(soc_info->mem_block[i]->start,
				resource_size(soc_info->mem_block[i]),
				soc_info->mem_block_name[i])){
				pr_err("Error Mem Region request Failed:%s\n",
					soc_info->mem_block_name[i]);
				rc = -ENOMEM;
				goto unmap_base;
			}
		}
		soc_info->reg_map[i].mem_base = ioremap(
			soc_info->mem_block[i]->start,
			resource_size(soc_info->mem_block[i]));
@@ -587,6 +1051,11 @@ int cam_soc_util_request_platform_resource(struct cam_hw_soc_info *soc_info,
	}

	for (i = 0; i < soc_info->num_rgltr; i++) {
		if (soc_info->rgltr_name[i] == NULL) {
			pr_err("can't find regulator name\n");
			goto put_regulator;
		}

		rc = cam_soc_util_get_regulator(pdev, &soc_info->rgltr[i],
			soc_info->rgltr_name[i]);
		if (rc)
@@ -597,7 +1066,7 @@ int cam_soc_util_request_platform_resource(struct cam_hw_soc_info *soc_info,
		rc = devm_request_irq(&pdev->dev, soc_info->irq_line->start,
			handler, IRQF_TRIGGER_RISING,
			soc_info->irq_name, irq_data);
		if (rc < 0) {
		if (rc) {
			pr_err("irq request fail\n");
			rc = -EBUSY;
			goto put_regulator;
@@ -617,6 +1086,16 @@ int cam_soc_util_request_platform_resource(struct cam_hw_soc_info *soc_info,
		}
	}

	rc = cam_soc_util_request_pinctrl(soc_info);
	if (rc)
		CDBG("Failed in request pinctrl, rc=%d\n", rc);

	rc = cam_soc_util_request_gpio_table(soc_info, true);
	if (rc) {
		pr_err("Failed in request gpio table, rc=%d\n", rc);
		goto put_clk;
	}

	return rc;

put_clk:
@@ -650,6 +1129,9 @@ int cam_soc_util_request_platform_resource(struct cam_hw_soc_info *soc_info,
	if (i == -1)
		i = soc_info->num_reg_map;
	for (i = i - 1; i >= 0; i--) {
		if (soc_info->reserve_mem)
			release_mem_region(soc_info->mem_block[i]->start,
				resource_size(soc_info->mem_block[i]));
		iounmap(soc_info->reg_map[i].mem_base);
		soc_info->reg_map[i].mem_base = NULL;
		soc_info->reg_map[i].size = 0;
@@ -663,8 +1145,11 @@ int cam_soc_util_release_platform_resource(struct cam_hw_soc_info *soc_info)
	int i;
	struct platform_device *pdev = NULL;

	if (!soc_info || !soc_info->pdev)
	if (!soc_info || !soc_info->pdev) {
		pr_err("Invalid parameter\n");
		return -EINVAL;
	}


	pdev = soc_info->pdev;

@@ -692,24 +1177,28 @@ int cam_soc_util_release_platform_resource(struct cam_hw_soc_info *soc_info)
			soc_info->irq_line->start, soc_info->irq_data);
	}

	if (soc_info->pinctrl_info.pinctrl)
		devm_pinctrl_put(soc_info->pinctrl_info.pinctrl);


	/* release for gpio */
	cam_soc_util_request_gpio_table(soc_info, false);

	return 0;
}

int cam_soc_util_enable_platform_resource(struct cam_hw_soc_info *soc_info,
	bool enable_clocks, enum cam_vote_level clk_level, bool enable_irq)
{
	int i, rc = 0;
	int rc = 0;

	if (!soc_info)
		return -EINVAL;

	for (i = 0; i < soc_info->num_rgltr; i++) {
		rc = regulator_enable(soc_info->rgltr[i]);
	rc = cam_soc_util_regulator_enable_default(soc_info);
	if (rc) {
			pr_err("Regulator enable %s failed\n",
				soc_info->rgltr_name[i]);
			goto disable_regulator;
		}
		pr_err("Regulators enable failed\n");
		return rc;
	}

	if (enable_clocks) {
@@ -724,19 +1213,28 @@ int cam_soc_util_enable_platform_resource(struct cam_hw_soc_info *soc_info,
			goto disable_clk;
	}

	if (soc_info->pinctrl_info.pinctrl &&
		soc_info->pinctrl_info.gpio_state_active) {
		rc = pinctrl_select_state(soc_info->pinctrl_info.pinctrl,
			soc_info->pinctrl_info.gpio_state_active);

		if (rc)
			goto disable_irq;
	}

	return rc;

disable_irq:
	if (enable_irq)
		cam_soc_util_irq_disable(soc_info);

disable_clk:
	if (enable_clocks)
		cam_soc_util_clk_disable_default(soc_info);

disable_regulator:
	if (i == -1)
		i = soc_info->num_rgltr;
	for (i = i - 1; i >= 0; i--) {
		if (soc_info->rgltr[i])
			regulator_disable(soc_info->rgltr[i]);
	}
	cam_soc_util_regulator_disable_default(soc_info);


	return rc;
}
@@ -744,7 +1242,7 @@ int cam_soc_util_enable_platform_resource(struct cam_hw_soc_info *soc_info,
int cam_soc_util_disable_platform_resource(struct cam_hw_soc_info *soc_info,
	bool disable_clocks, bool disble_irq)
{
	int i, rc = 0;
	int rc = 0;

	if (!soc_info)
		return -EINVAL;
@@ -752,18 +1250,16 @@ int cam_soc_util_disable_platform_resource(struct cam_hw_soc_info *soc_info,
	if (disable_clocks)
		cam_soc_util_clk_disable_default(soc_info);

	for (i = soc_info->num_rgltr - 1; i >= 0; i--) {
		rc |= regulator_disable(soc_info->rgltr[i]);
		if (rc) {
			pr_err("Regulator disble %s failed\n",
				soc_info->rgltr_name[i]);
			continue;
		}
	}
	cam_soc_util_regulator_disable_default(soc_info);

	if (disble_irq)
		rc |= cam_soc_util_irq_disable(soc_info);

	if (soc_info->pinctrl_info.pinctrl &&
		soc_info->pinctrl_info.gpio_state_suspend)
		rc = pinctrl_select_state(soc_info->pinctrl_info.pinctrl,
			soc_info->pinctrl_info.gpio_state_suspend);

	return rc;
}

+91 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>

@@ -59,6 +60,10 @@ enum cam_vote_level {
	CAM_MAX_VOTE,
};

/* pinctrl states */
#define CAM_SOC_PINCTRL_STATE_SLEEP "cam_suspend"
#define CAM_SOC_PINCTRL_STATE_DEFAULT "cam_default"

/**
 * struct cam_soc_reg_map:   Information about the mapped register space
 *
@@ -73,6 +78,35 @@ struct cam_soc_reg_map {
	resource_size_t                 size;
};

/**
 * struct cam_soc_pinctrl_info:   Information about pinctrl data
 *
 * @pinctrl:               pintrl object
 * @gpio_state_active:     default pinctrl state
 * @gpio_state_suspend     suspend state of pinctrl
 **/
struct cam_soc_pinctrl_info {
	struct pinctrl *pinctrl;
	struct pinctrl_state *gpio_state_active;
	struct pinctrl_state *gpio_state_suspend;
};

/**
 * struct cam_soc_gpio_data:   Information about the gpio pins
 *
 * @cam_gpio_common_tbl:       It is list of al the gpios present in gpios node
 * @cam_gpio_common_tbl_size:  It is equal to number of gpios prsent in
 *                             gpios node in DTSI
 * @cam_gpio_req_tbl            It is list of al the requesetd gpios
 * @cam_gpio_req_tbl_size:      It is size of requested gpios
 **/
struct cam_soc_gpio_data {
	struct gpio *cam_gpio_common_tbl;
	uint8_t cam_gpio_common_tbl_size;
	struct gpio *cam_gpio_req_tbl;
	uint8_t cam_gpio_req_tbl_size;
};

/**
 * struct cam_hw_soc_info:  Soc information pertaining to specific instance of
 *                          Camera hardware driver module
@@ -92,9 +126,16 @@ struct cam_soc_reg_map {
 * @num_reg_map:            Number of mapped register space associated
 *                          with mem_block. num_reg_map = num_mem_block in
 *                          most cases
 * @reserve_mem:            Whether to reserve memory for Mem blocks
 * @num_rgltr:              Number of regulators
 * @rgltr_name:             Array of regulator names
 * @rgltr_ctrl_support:     Whether regulator control is supported
 * @rgltr_min_volt:         Array of minimum regulator voltage
 * @rgltr_max_volt:         Array of maximum regulator voltage
 * @rgltr_op_mode:          Array of regulator operation mode
 * @rgltr_type:             Array of regulator names
 * @rgltr:                  Array of associated regulator resources
 * @rgltr_delay:            Array of regulator delay values
 * @num_clk:                Number of clocks
 * @clk_name:               Array of clock names
 * @clk:                    Array of associated clock resources
@@ -102,6 +143,8 @@ struct cam_soc_reg_map {
 *                          values at different vote levels
 * @src_clk_idx:            Source clock index that is rate-controllable
 * @clk_level_valid:        Indicates whether corresponding level is valid
 * @gpio_data:              Pointer to gpio info
 * @pinctrl_info:           Pointer to pinctrl info
 * @soc_private:            Soc private data
 *
 */
@@ -109,7 +152,6 @@ struct cam_hw_soc_info {
	struct platform_device         *pdev;
	uint32_t                        hw_version;
	uint32_t                        index;

	const char                     *irq_name;
	struct resource                *irq_line;
	void                           *irq_data;
@@ -120,10 +162,17 @@ struct cam_hw_soc_info {
	struct resource                *mem_block[CAM_SOC_MAX_BLOCK];
	struct cam_soc_reg_map          reg_map[CAM_SOC_MAX_BASE];
	uint32_t                        num_reg_map;
	uint32_t                        reserve_mem;

	uint32_t                        num_rgltr;
	const char                     *rgltr_name[CAM_SOC_MAX_REGULATOR];
	uint32_t                        rgltr_ctrl_support;
	uint32_t                        rgltr_min_volt[CAM_SOC_MAX_REGULATOR];
	uint32_t                        rgltr_max_volt[CAM_SOC_MAX_REGULATOR];
	uint32_t                        rgltr_op_mode[CAM_SOC_MAX_REGULATOR];
	uint32_t                        rgltr_type[CAM_SOC_MAX_REGULATOR];
	struct regulator               *rgltr[CAM_SOC_MAX_REGULATOR];
	uint32_t                        rgltr_delay[CAM_SOC_MAX_REGULATOR];

	uint32_t                        num_clk;
	const char                     *clk_name[CAM_SOC_MAX_CLK];
@@ -132,6 +181,8 @@ struct cam_hw_soc_info {
	int32_t                         src_clk_idx;
	bool                            clk_level_valid[CAM_MAX_VOTE];

	struct cam_soc_gpio_data       *gpio_data;
	struct cam_soc_pinctrl_info     pinctrl_info;

	void                           *soc_private;
};
@@ -340,6 +391,45 @@ int cam_soc_util_irq_enable(struct cam_hw_soc_info *soc_info);
 */
int cam_soc_util_irq_disable(struct cam_hw_soc_info *soc_info);

/**
 * cam_soc_util_regulator_enable()
 *
 * @brief:              Enable single regulator
 *
 * @rgltr               Regulator that needs to be turned ON
 * @rgltr_name          Associated Regulator name
 * @rgltr_min_volt:     Requested minimum volatage
 * @rgltr_max_volt:     Requested maximum volatage
 * @rgltr_op_mode:      Requested Load
 * @rgltr_delay:        Requested delay needed aaftre enabling regulator
 *
 * @return:             Success or failure
 */
int cam_soc_util_regulator_enable(struct regulator *rgltr,
	const char *rgltr_name,
	uint32_t rgltr_min_volt, uint32_t rgltr_max_volt,
	uint32_t rgltr_op_mode, uint32_t rgltr_delay);

/**
 * cam_soc_util_regulator_enable()
 *
 * @brief:              Disable single regulator
 *
 * @rgltr               Regulator that needs to be turned ON
 * @rgltr_name          Associated Regulator name
 * @rgltr_min_volt:     Requested minimum volatage
 * @rgltr_max_volt:     Requested maximum volatage
 * @rgltr_op_mode:      Requested Load
 * @rgltr_delay:        Requested delay needed aaftre enabling regulator
 *
 * @return:             Success or failure
 */
int cam_soc_util_regulator_disable(struct regulator *rgltr,
	const char *rgltr_name,
	uint32_t rgltr_min_volt, uint32_t rgltr_max_volt,
	uint32_t rgltr_op_mode, uint32_t rgltr_delay);


/**
 * cam_soc_util_w()
 *