Commit f8cef982 authored by Ivaylo Ivanov's avatar Ivaylo Ivanov Committed by Andi Shyti
Browse files

i2c: exynos5: Add support for Exynos8895 SoC



Exynos8895 functioning logic mostly follows I2C_TYPE_EXYNOS7, but timing
and temp calculations are slightly different according to the following
logic:

FPCLK / FI2C = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 2 *
((FLT_CYCLE + 3) - (FLT_CYCLE + 3) % (CLK_DIV + 1))

temp := (FPCLK / FI2C) - (FLT_CYCLE + 3) * 2

Signed-off-by: default avatarIvaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
Link: https://lore.kernel.org/r/20241228111509.896502-3-ivo.ivanov.ivanov1@gmail.com


Signed-off-by: default avatarAndi Shyti <andi.shyti@kernel.org>
parent 01aa0281
Loading
Loading
Loading
Loading
+31 −4
Original line number Diff line number Diff line
@@ -168,6 +168,7 @@ enum i2c_type_exynos {
	I2C_TYPE_EXYNOS5,
	I2C_TYPE_EXYNOS7,
	I2C_TYPE_EXYNOSAUTOV9,
	I2C_TYPE_EXYNOS8895,
};

struct exynos5_i2c {
@@ -240,6 +241,11 @@ static const struct exynos_hsi2c_variant exynosautov9_hsi2c_data = {
	.hw		= I2C_TYPE_EXYNOSAUTOV9,
};

static const struct exynos_hsi2c_variant exynos8895_hsi2c_data = {
	.fifo_depth	= 64,
	.hw		= I2C_TYPE_EXYNOS8895,
};

static const struct of_device_id exynos5_i2c_match[] = {
	{
		.compatible = "samsung,exynos5-hsi2c",
@@ -256,6 +262,9 @@ static const struct of_device_id exynos5_i2c_match[] = {
	}, {
		.compatible = "samsung,exynosautov9-hsi2c",
		.data = &exynosautov9_hsi2c_data
	}, {
		.compatible = "samsung,exynos8895-hsi2c",
		.data = &exynos8895_hsi2c_data
	}, {},
};
MODULE_DEVICE_TABLE(of, exynos5_i2c_match);
@@ -331,6 +340,14 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings)
	 * clk_cycle := TSCLK_L + TSCLK_H
	 * temp := (CLK_DIV + 1) * (clk_cycle + 2)
	 *
	 * In case of HSI2C controllers in Exynos8895
	 * FPCLK / FI2C =
	 * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) +
	 * 2 * ((FLT_CYCLE + 3) - (FLT_CYCLE + 3) % (CLK_DIV + 1))
	 *
	 * clk_cycle := TSCLK_L + TSCLK_H
	 * temp := (FPCLK / FI2C) - (FLT_CYCLE + 3) * 2
	 *
	 * Constraints: 4 <= temp, 0 <= CLK_DIV < 256, 2 <= clk_cycle <= 510
	 *
	 * To split SCL clock into low, high periods appropriately, one
@@ -352,10 +369,18 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings)
	 *
	 */
	t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7;
	if (i2c->variant->hw == I2C_TYPE_EXYNOS8895)
		temp = clkin / op_clk - (t_ftl_cycle + 3) * 2;
	else if (i2c->variant->hw == I2C_TYPE_EXYNOS7)
		temp = clkin / op_clk - 8 - t_ftl_cycle;
	if (i2c->variant->hw != I2C_TYPE_EXYNOS7)
		temp -= t_ftl_cycle;
	else
		temp = clkin / op_clk - 8 - (t_ftl_cycle * 2);
	div = temp / 512;

	if (i2c->variant->hw == I2C_TYPE_EXYNOS8895)
		clk_cycle = (temp + ((t_ftl_cycle + 3) % (div + 1)) * 2) /
			    (div + 1) - 2;
	else
		clk_cycle = temp / (div + 1) - 2;
	if (temp < 4 || div >= 256 || clk_cycle < 2) {
		dev_err(i2c->dev, "%s clock set-up failed\n",
@@ -491,6 +516,8 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)
	switch (i2c->variant->hw) {
	case I2C_TYPE_EXYNOSAUTOV9:
		fallthrough;
	case I2C_TYPE_EXYNOS8895:
		fallthrough;
	case I2C_TYPE_EXYNOS7:
		if (int_status & HSI2C_INT_TRANS_DONE) {
			i2c->trans_done = 1;