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

Commit 6f23120b authored by Shrey Vijay's avatar Shrey Vijay
Browse files

i2c: qcom: geni: Add support for Standard, Fast and Fast plus modes



Add support for Standard, Fast and Fast plus modes of frequency.
Devicetree property should be added as per the slave requirement.
I2C driver sets to Fast mode if property is not specified
in DT file.

Signed-off-by: default avatarShrey Vijay <shreyv@codeaurora.org>
Change-Id: Ie7c9d658f312c82d5a708ff624acbdcdcb3b8438
parent 4d9a308b
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -14,6 +14,10 @@ Required properties:
 - #size-cells: Should be <0> as i2c addresses have no size component
 - qcom,wrapper-core: Wrapper QUPv3 core containing this I2C controller.

Optional property:
 - qcom,clk-freq-out : Desired I2C bus clock frequency in Hz.
   When missing default to 400000Hz.

Child nodes should conform to i2c bus binding.

Example:
@@ -32,4 +36,5 @@ i2c@a94000 {
	#address-cells = <1>;
	#size-cells = <0>;
	qcom,wrapper-core = <&qupv3_0>;
	qcom,clk-freq-out = <400000>;
};
+63 −8
Original line number Diff line number Diff line
@@ -85,6 +85,7 @@ struct geni_i2c_dev {
	int cur_rd;
	struct device *wrapper_dev;
	void *ipcl;
	int clk_fld_idx;
};

struct geni_i2c_err_log {
@@ -109,12 +110,52 @@ static struct geni_i2c_err_log gi2c_log[] = {
	[GENI_TIMEOUT] = {-ETIMEDOUT, "I2C TXN timed out"},
};

static inline void qcom_geni_i2c_conf(void __iomem *base, int dfs, int div)
struct geni_i2c_clk_fld {
	u32	clk_freq_out;
	u8	clk_div;
	u8	t_high;
	u8	t_low;
	u8	t_cycle;
};

static struct geni_i2c_clk_fld geni_i2c_clk_map[] = {
	{KHz(100), 7, 10, 11, 26},
	{KHz(400), 2,  5, 12, 24},
	{KHz(1000), 1, 3,  9, 18},
};

static int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c)
{
	geni_write_reg(dfs, base, SE_GENI_CLK_SEL);
	geni_write_reg((div << 4) | 1, base, GENI_SER_M_CLK_CFG);
	geni_write_reg(((5 << 20) | (0xC << 10) | 0x18),
				base, SE_I2C_SCL_COUNTERS);
	int i;
	int ret = 0;
	bool clk_map_present = false;
	struct geni_i2c_clk_fld *itr = geni_i2c_clk_map;

	for (i = 0; i < ARRAY_SIZE(geni_i2c_clk_map); i++, itr++) {
		if (itr->clk_freq_out == gi2c->i2c_rsc.clk_freq_out) {
			clk_map_present = true;
			break;
		}
	}

	if (clk_map_present)
		gi2c->clk_fld_idx = i;
	else
		ret = -EINVAL;

	return ret;
}

static inline void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c, int dfs)
{
	struct geni_i2c_clk_fld *itr = geni_i2c_clk_map + gi2c->clk_fld_idx;

	geni_write_reg(dfs, gi2c->base, SE_GENI_CLK_SEL);

	geni_write_reg((itr->clk_div << 4) | 1, gi2c->base, GENI_SER_M_CLK_CFG);
	geni_write_reg(((itr->t_high << 20) | (itr->t_low << 10) |
			itr->t_cycle), gi2c->base, SE_I2C_SCL_COUNTERS);

	/*
	* Ensure Clk config completes before return.
	*/
@@ -283,7 +324,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
		pm_runtime_set_suspended(gi2c->dev);
		return ret;
	}
	qcom_geni_i2c_conf(gi2c->base, 0, 2);
	qcom_geni_i2c_conf(gi2c, 0);
	dev_dbg(gi2c->dev, "i2c xfer:num:%d, msgs:len:%d,flg:%d\n",
				num, msgs[0].len, msgs[0].flags);
	for (i = 0; i < num; i++) {
@@ -485,12 +526,26 @@ static int geni_i2c_probe(struct platform_device *pdev)
		return ret;
	}

	if (of_property_read_u32(pdev->dev.of_node, "qcom,clk-freq-out",
				&gi2c->i2c_rsc.clk_freq_out)) {
		dev_info(&pdev->dev,
			"Bus frequency not specified, default to 400KHz.\n");
		gi2c->i2c_rsc.clk_freq_out = KHz(400);
	}

	gi2c->irq = platform_get_irq(pdev, 0);
	if (gi2c->irq < 0) {
		dev_err(gi2c->dev, "IRQ error for i2c-geni\n");
		return gi2c->irq;
	}

	ret = geni_i2c_clk_map_idx(gi2c);
	if (ret) {
		dev_err(gi2c->dev, "Invalid clk frequency %d KHz: %d\n",
				gi2c->i2c_rsc.clk_freq_out, ret);
		return ret;
	}

	gi2c->adap.algo = &geni_i2c_algo;
	init_completion(&gi2c->xfer);
	platform_set_drvdata(pdev, gi2c);
+3 −0
Original line number Diff line number Diff line
@@ -64,11 +64,14 @@ struct se_geni_rsc {
	struct pinctrl *geni_pinctrl;
	struct pinctrl_state *geni_gpio_active;
	struct pinctrl_state *geni_gpio_sleep;
	int	clk_freq_out;
};

#define PINCTRL_DEFAULT	"default"
#define PINCTRL_SLEEP	"sleep"

#define KHz(freq) (1000 * (freq))

/* Common SE registers */
#define GENI_INIT_CFG_REVISION		(0x0)
#define GENI_S_INIT_CFG_REVISION	(0x4)