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

Commit d2b4d73e authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: camera: Support for 1Mhz I2C speed"

parents c0f7bf86 2c6ccbf7
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,
};