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

Commit 2c6ccbf7 authored by Evgeniy Borisov's avatar Evgeniy Borisov
Browse files

msm: camera: Support for 1Mhz I2C speed



For custom I2C camera device is need 1Mhz clock.
Currently supported I2C speeds are 100Khz and 400Khz.
For 1Mhz we can change CCI source clock because we
can not able to come up all I2C speed configuration
from 19,2Mhz source.

Change-Id: I22ea5200ab80713daaf40ae40f76073784f1fae9
Signed-off-by: default avatarEvgeniy Borisov <eborisov@codeaurora.org>
parent b9e32abd
Loading
Loading
Loading
Loading
+28 −7
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ Required properties:

Optional properties:
- qcom,gdscr-vdd-supply : should contain regulator used for cci clocks

- I2c speed settings (*)
	- i2c_freq_100Khz: qcom,i2c_standard_mode - node should contain clock settings for
	    100Khz
	- i2c_freq_400Khz: qcom,i2c_fast_mode - node should contain clock settings for
@@ -30,6 +32,10 @@ Optional properties:
	- i2c_freq_custom: qcom,i2c_custom_mode - node can contain clock settings for
	    frequencies other than 100Khz and 400Khz which is specific to usecase.
	    Currently it has settings for 375Khz.
	- i2c_freq_1Mhz: qcom,i2c_fast_plus_mode - node should contain clock
	    settings for 1Mhz
	* if speed settings is not defined the low level driver can use "i2c_freq_custom"
	  like default

[Second level nodes]
* Qualcomm CCI clock settings
@@ -350,3 +356,18 @@ Example:
	qcom,hw-tsp = <3>;
	status = "ok";
};

&i2c_freq_1Mhz {
	qcom,hw-thigh = <16>;
	qcom,hw-tlow = <22>;
	qcom,hw-tsu-sto = <17>;
	qcom,hw-tsu-sta = <18>;
	qcom,hw-thd-dat = <16>;
	qcom,hw-thd-sta = <15>;
	qcom,hw-tbuf = <19>;
	qcom,hw-scl-stretch-en = <1>;
	qcom,hw-trdhld = <3>;
	qcom,hw-tsp = <3>;
	qcom,cci-clk-src = <37500000>;
	status = "ok";
};
+120 −41
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@

static struct v4l2_subdev *g_cci_subdev;

static struct msm_cam_clk_info cci_clk_info[CCI_NUM_CLK_MAX];
static struct msm_cam_clk_info cci_clk_info[CCI_NUM_CLK_CASES][CCI_NUM_CLK_MAX];

static void msm_cci_set_clk_param(struct cci_device *cci_dev,
	struct msm_camera_cci_ctrl *c_ctrl)
@@ -685,6 +685,59 @@ static int32_t msm_cci_pinctrl_init(struct cci_device *cci_dev)
	return 0;
}

static uint32_t msm_cci_cycles_per_ms(unsigned long clk)
{
	uint32_t cycles_per_us;

	if (clk)
		cycles_per_us = ((clk/1000)*256)/1000;
	else {
		pr_err("%s:%d, failed: Can use default: %d",
			__func__, __LINE__, CYCLES_PER_MICRO_SEC_DEFAULT);
		cycles_per_us = CYCLES_PER_MICRO_SEC_DEFAULT;
	}
	return cycles_per_us;
}

static struct msm_cam_clk_info *msm_cci_get_clk(struct cci_device *cci_dev,
	struct msm_camera_cci_ctrl *c_ctrl)
{
	uint32_t j;
	int32_t idx;
	uint32_t cci_clk_src;
	unsigned long clk;

	struct msm_cci_clk_params_t *clk_params = NULL;
	enum i2c_freq_mode_t i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode;
	struct device_node *of_node = cci_dev->pdev->dev.of_node;
	clk_params = &cci_dev->cci_clk_params[i2c_freq_mode];
	cci_clk_src = clk_params->cci_clk_src;

	idx = of_property_match_string(of_node,
		"clock-names", CCI_CLK_SRC_NAME);
	if (idx < 0) {
		cci_dev->cycles_per_us = CYCLES_PER_MICRO_SEC_DEFAULT;
		return &cci_clk_info[0][0];
	}

	if (cci_clk_src == 0) {
		clk = cci_clk_info[0][idx].clk_rate;
		cci_dev->cycles_per_us = msm_cci_cycles_per_ms(clk);
		return &cci_clk_info[0][0];
	}

	for (j = 0; j < cci_dev->num_clk_cases; j++) {
		clk = cci_clk_info[j][idx].clk_rate;
		if (clk == cci_clk_src) {
			cci_dev->cycles_per_us = msm_cci_cycles_per_ms(clk);
			cci_dev->cci_clk_src = cci_clk_src;
			return &cci_clk_info[j][0];
		}
	}

	return NULL;
}

static int32_t msm_cci_init(struct v4l2_subdev *sd,
	struct msm_camera_cci_ctrl *c_ctrl)
{
@@ -692,6 +745,7 @@ static int32_t msm_cci_init(struct v4l2_subdev *sd,
	int32_t rc = 0, ret = 0;
	struct cci_device *cci_dev;
	enum cci_i2c_master_t master;
	struct msm_cam_clk_info *clk_info = NULL;

	cci_dev = v4l2_get_subdevdata(sd);
	if (!cci_dev || !c_ctrl) {
@@ -762,7 +816,14 @@ static int32_t msm_cci_init(struct v4l2_subdev *sd,
			goto clk_enable_failed;
		}
	}
	rc = msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info,

	clk_info = msm_cci_get_clk(cci_dev, c_ctrl);
	if (!clk_info) {
		pr_err("%s: clk enable failed\n", __func__);
		goto clk_enable_failed;
	}

	rc = msm_cam_clk_enable(&cci_dev->pdev->dev, clk_info,
		cci_dev->cci_clk, cci_dev->num_clk, 1);
	if (rc < 0) {
		CDBG("%s: clk enable failed\n", __func__);
@@ -801,7 +862,7 @@ static int32_t msm_cci_init(struct v4l2_subdev *sd,

reset_complete_failed:
	disable_irq(cci_dev->irq->start);
	msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info,
	msm_cam_clk_enable(&cci_dev->pdev->dev, clk_info,
		cci_dev->cci_clk, cci_dev->num_clk, 0);
clk_enable_failed:
	if (cci_dev->cci_pinctrl_status) {
@@ -840,7 +901,7 @@ static int32_t msm_cci_release(struct v4l2_subdev *sd)
		return 0;
	}
	disable_irq(cci_dev->irq->start);
	msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info,
	msm_cam_clk_enable(&cci_dev->pdev->dev, &cci_clk_info[0][0],
		cci_dev->cci_clk, cci_dev->num_clk, 0);
	if (!IS_ERR_OR_NULL(cci_dev->reg_ptr)) {
		regulator_disable(cci_dev->reg_ptr);
@@ -860,6 +921,8 @@ static int32_t msm_cci_release(struct v4l2_subdev *sd)
	for (i = 0; i < MASTER_MAX; i++)
		cci_dev->master_clk_init[i] = 0;
	cci_dev->cci_state = CCI_STATE_DISABLED;
	cci_dev->cycles_per_us = 0;
	cci_dev->cci_clk_src = 0;

	return 0;
}
@@ -1104,6 +1167,7 @@ static void msm_cci_init_default_clk_params(struct cci_device *cci_dev,
	cci_dev->cci_clk_params[index].hw_scl_stretch_en = 0;
	cci_dev->cci_clk_params[index].hw_trdhld = 6;
	cci_dev->cci_clk_params[index].hw_tsp = 1;
	cci_dev->cci_clk_params[index].cci_clk_src = 19200000;
}

static void msm_cci_init_clk_params(struct cci_device *cci_dev)
@@ -1122,6 +1186,9 @@ static void msm_cci_init_clk_params(struct cci_device *cci_dev)
		else if (I2C_FAST_MODE == count)
			src_node = of_find_node_by_name(of_node,
				"qcom,i2c_fast_mode");
		else if (I2C_FAST_PLUS_MODE == count)
			src_node = of_find_node_by_name(of_node,
				"qcom,i2c_fast_plus_mode");
		else
			src_node = of_find_node_by_name(of_node,
				"qcom,i2c_custom_mode");
@@ -1188,10 +1255,20 @@ static void msm_cci_init_clk_params(struct cci_device *cci_dev)
				&val);
			CDBG("%s qcom,hw-tsp %d, rc %d\n", __func__, val, rc);
		}
		if (!rc)
		if (!rc) {
			cci_dev->cci_clk_params[count].hw_tsp = val;
			val = 0;
			rc = of_property_read_u32(src_node, "qcom,cci-clk-src",
				&val);
			CDBG("%s qcom,cci-clk-src %d, rc %d\n",
				__func__, val, rc);
			cci_dev->cci_clk_params[count].cci_clk_src = val;
		}
		else
			msm_cci_init_default_clk_params(cci_dev, count);



		of_node_put(src_node);
		src_node = NULL;
	}
@@ -1207,8 +1284,10 @@ static int msm_cci_get_clk_info(struct cci_device *cci_dev,
	struct platform_device *pdev)
{
	uint32_t count;
	int i, rc;
	uint32_t rates[CCI_NUM_CLK_MAX];
	uint32_t count_r;
	int i, j, rc;
	const uint32_t *p;
	int index = 0;

	struct device_node *of_node;
	of_node = pdev->dev.of_node;
@@ -1229,46 +1308,47 @@ static int msm_cci_get_clk_info(struct cci_device *cci_dev,
		return -EINVAL;
	}

	for (i = 0; i < count; i++) {
		rc = of_property_read_string_index(of_node, "clock-names",
				i, &(cci_clk_info[i].clk_name));
		CDBG("%s: clock-names[%d] = %s\n", __func__,
			i, cci_clk_info[i].clk_name);
		if (rc < 0) {
			pr_err("%s:%d, failed\n", __func__, __LINE__);
			return rc;
	p = of_get_property(of_node, "qcom,clock-rates", &count_r);
	if (!p || !count_r) {
		pr_err("failed\n");
		return -EINVAL;
	}

	count_r /= sizeof(uint32_t);
	cci_dev->num_clk_cases = count_r/count;

	if (cci_dev->num_clk_cases > CCI_NUM_CLK_CASES) {
		pr_err("%s: invalid count=%d, max is %d\n", __func__,
			cci_dev->num_clk_cases, CCI_NUM_CLK_CASES);
		return -EINVAL;
	}
	rc = of_property_read_u32_array(of_node, "qcom,clock-rates",
		rates, count);

	index = 0;
	for (i = 0; i < count_r/count; i++) {
		for (j = 0; j < count; j++) {
			rc = of_property_read_string_index(of_node,
				"clock-names", j,
				&(cci_clk_info[i][j].clk_name));
			pr_err("%s: clock-names[%d][%d] = %s\n", __func__,
				i, j, cci_clk_info[i][j].clk_name);
			if (rc < 0) {
		pr_err("%s:%d, failed", __func__, __LINE__);
				pr_err("%s:%d, failed\n", __func__, __LINE__);
				return rc;
			}
	for (i = 0; i < count; i++) {
		cci_clk_info[i].clk_rate = (rates[i] == 0) ?
			(long)-1 : rates[i];
		CDBG("%s: clk_rate[%d] = %ld\n", __func__, i,
			cci_clk_info[i].clk_rate);
	}
	return 0;
}

static uint32_t msm_get_cycles_per_ms(void)
{
	int i = 0;
	for (i = 0; i < CCI_NUM_CLK_MAX; i++) {
		if (!strcmp(cci_clk_info[i].clk_name, "cci_src_clk")) {
			CDBG("%s:%d i %d cci_src_clk\n",
				__func__, __LINE__, i);
			return ((cci_clk_info[i].clk_rate/1000)*256)/1000;
			cci_clk_info[i][j].clk_rate =
				(be32_to_cpu(p[index]) == 0) ?
					(long)-1 : be32_to_cpu(p[index]);
			pr_err("%s: clk_rate[%d][%d] = %ld\n", __func__, i, j,
				cci_clk_info[i][j].clk_rate);
			index++;
		}
	}
	pr_err("%s:%d, failed: Can use default: %d",
		__func__, __LINE__, CYCLES_PER_MICRO_SEC_DEFAULT);
	return CYCLES_PER_MICRO_SEC_DEFAULT;
	return 0;
}



static int msm_cci_probe(struct platform_device *pdev)
{
	struct cci_device *new_cci_dev;
@@ -1298,7 +1378,6 @@ static int msm_cci_probe(struct platform_device *pdev)
		return -EFAULT;
	}

	new_cci_dev->cycles_per_us = msm_get_cycles_per_ms();
	new_cci_dev->ref_count = 0;
	new_cci_dev->mem = platform_get_resource_byname(pdev,
					IORESOURCE_MEM, "cci");
+6 −0
Original line number Diff line number Diff line
@@ -31,6 +31,9 @@
#define CCI_PINCTRL_STATE_SLEEP "cci_suspend"

#define CCI_NUM_CLK_MAX	16
#define CCI_NUM_CLK_CASES 5
#define CCI_CLK_SRC_NAME "cci_src_clk"


enum cci_i2c_queue_t {
	QUEUE_0,
@@ -115,6 +118,7 @@ struct msm_cci_clk_params_t {
	uint8_t hw_scl_stretch_en;
	uint8_t hw_trdhld;
	uint8_t hw_tsp;
	uint32_t cci_clk_src;
};

enum msm_cci_state_t {
@@ -135,6 +139,7 @@ struct cci_device {
	uint8_t ref_count;
	enum msm_cci_state_t cci_state;
	uint32_t num_clk;
	uint32_t num_clk_cases;

	struct clk *cci_clk[CCI_NUM_CLK_MAX];
	struct msm_camera_cci_i2c_queue_info
@@ -148,6 +153,7 @@ struct cci_device {
	uint8_t cci_pinctrl_status;
	struct regulator *reg_ptr;
	uint32_t cycles_per_us;
	uint32_t cci_clk_src;
};

enum msm_cci_i2c_cmd_type {
+1 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ enum i2c_freq_mode_t {
	I2C_STANDARD_MODE,
	I2C_FAST_MODE,
	I2C_CUSTOM_MODE,
	I2C_FAST_PLUS_MODE,
	I2C_MAX_MODES,
};