summaryrefslogtreecommitdiff
path: root/drivers/i2c/busses/i2c-exynos5.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/busses/i2c-exynos5.c')
-rw-r--r--drivers/i2c/busses/i2c-exynos5.c43
1 files changed, 35 insertions, 8 deletions
diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c
index e330015087ab..9c1c5f3c09f6 100644
--- a/drivers/i2c/busses/i2c-exynos5.c
+++ b/drivers/i2c/busses/i2c-exynos5.c
@@ -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,11 +369,19 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings)
*
*/
t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7;
- temp = clkin / op_clk - 8 - t_ftl_cycle;
- if (i2c->variant->hw != I2C_TYPE_EXYNOS7)
- temp -= t_ftl_cycle;
+ 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;
+ else
+ temp = clkin / op_clk - 8 - (t_ftl_cycle * 2);
div = temp / 512;
- clk_cycle = temp / (div + 1) - 2;
+
+ 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",
hs_timings ? "HS" : "FS");
@@ -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;
@@ -787,7 +814,7 @@ static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c,
ret = i2c->state;
/*
- * If this is the last message to be transfered (stop == 1)
+ * If this is the last message to be transferred (stop == 1)
* Then check if the bus can be brought back to idle.
*/
if (ret == 0 && stop)
@@ -852,9 +879,9 @@ static u32 exynos5_i2c_func(struct i2c_adapter *adap)
}
static const struct i2c_algorithm exynos5_i2c_algorithm = {
- .master_xfer = exynos5_i2c_xfer,
- .master_xfer_atomic = exynos5_i2c_xfer_atomic,
- .functionality = exynos5_i2c_func,
+ .xfer = exynos5_i2c_xfer,
+ .xfer_atomic = exynos5_i2c_xfer_atomic,
+ .functionality = exynos5_i2c_func,
};
static int exynos5_i2c_probe(struct platform_device *pdev)