[COMMON] i2c: exynos5: reset i2c master before suspend
authorYoungmin Nam <youngmin.nam@samsung.com>
Fri, 29 Jul 2016 05:16:45 +0000 (14:16 +0900)
committermyung-su.cha <myung-su.cha@samsung.com>
Wed, 9 May 2018 12:14:45 +0000 (21:14 +0900)
This patch resets i2c master before suspend to prevent central secquence
stuck. If master state is in arbitration lose, I2C master requests
clock for operation. So we need to reset i2c master to recover from
arbitration lose state.

Change-Id: I5f5996b38148868b1fac26d2b81284ae7a9ad1f3
Signed-off-by: Youngmin Nam <youngmin.nam@samsung.com>
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-exynos5.c

index 45a3f3ca29b383ce7edfbb34e6d3fd506c5173b6..0f488bd7405329e39b5adfbda1bd36e1a7f915b9 100644 (file)
@@ -590,6 +590,14 @@ config I2C_EXYNOS5
        help
          High-speed I2C controller on Exynos5 based Samsung SoCs.
 
+config I2C_SAMSUNG_HWACG
+       bool "HWACG(HW Auto Clock Gating) support for Exynos I2C port"
+       default y
+       help
+       If HWACG is enabled on I2C, System power mode will goes into
+       suspend state only when I2C master is not in busy state.
+       To support HWACG on I2C, this configuration should be selected.
+
 config I2C_GPIO
        tristate "GPIO-based bitbanging I2C"
        depends on GPIOLIB || COMPILE_TEST
index 9e07d783a258da40ad69e281111a5b51cde7c70e..7b1cd37dd9bddcd772613e7c3b51dba1be73ad32 100644 (file)
@@ -1122,9 +1122,25 @@ static int exynos5_i2c_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int exynos5_i2c_suspend_noirq(struct device *dev)
 {
-       struct exynos5_i2c *i2c = dev_get_drvdata(dev);
+       struct platform_device *pdev = to_platform_device(dev);
+       struct exynos5_i2c *i2c = platform_get_drvdata(pdev);
+#ifdef CONFIG_I2C_SAMSUNG_HWACG
+       int ret = 0;
+#endif
 
        i2c_lock_adapter(&i2c->adap);
+#ifdef CONFIG_I2C_SAMSUNG_HWACG
+       exynos_update_ip_idle_status(i2c->idle_ip_index, 0);
+       ret = clk_enable(i2c->clk);
+       if (ret) {
+               exynos_update_ip_idle_status(i2c->idle_ip_index, 1);
+               i2c_unlock_adapter(&i2c->adap);
+               return ret;
+       }
+       exynos5_i2c_reset(i2c);
+       clk_disable(i2c->clk);
+       exynos_update_ip_idle_status(i2c->idle_ip_index, 1);
+#endif
        i2c->suspended = 1;
        i2c_unlock_adapter(&i2c->adap);