i2c: s3c2410: hw init after LPA
authorEunki Kim <eunki_kim@samsung.com>
Wed, 22 Jan 2014 03:22:56 +0000 (12:22 +0900)
committermyung-su.cha <myung-su.cha@samsung.com>
Thu, 10 May 2018 04:40:43 +0000 (13:40 +0900)
Signed-off-by: Eunki Kim <eunki_kim@samsung.com>
Conflicts:

drivers/i2c/busses/i2c-s3c2410.c

Change-Id: Ie61c476af4a56e94611051434453bcfc34df89be

drivers/i2c/busses/i2c-s3c2410.c

index 2fa1b44617f8489b47b5530bd0317571089d756e..1d6cc844c8c5874b900ca0d633bb93c2de4cfeb0 100644 (file)
 
 #include <linux/platform_data/i2c-s3c2410.h>
 
+#include <mach/exynos-pm.h>
+
+static LIST_HEAD(drvdata_list);
+
 /* see s3c2410x user guide, v1.1, section 9 (p447) for more info */
 
 #define S3C2410_IICCON                 0x00
@@ -102,8 +106,10 @@ enum s3c24xx_i2c_state {
 };
 
 struct s3c24xx_i2c {
+       struct list_head        node;
        wait_queue_head_t       wait;
        kernel_ulong_t          quirks;
+       unsigned int            need_hw_init;
        unsigned int            suspended:1;
 
        struct i2c_msg          *msg;
@@ -819,6 +825,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
  * first port of call from the i2c bus code when an message needs
  * transferring across the i2c bus.
 */
+static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c);
 
 static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
                        struct i2c_msg *msgs, int num)
@@ -826,20 +833,14 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
        struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;
        int retry;
        int ret;
-       unsigned int freq;
 
        pm_runtime_get_sync(&adap->dev);
        ret = clk_enable(i2c->clk);
        if (ret)
                return ret;
 
-       if (i2c->quirks & QUIRK_FIMC_I2C) {
-               ret = s3c24xx_i2c_clockrate(i2c, &freq);
-               if (ret < 0) {
-                       dev_err(i2c->dev, "cannot find frequency\n");
-                       return ret;
-               }
-       }
+       if (i2c->need_hw_init)
+               s3c24xx_i2c_init(i2c);
 
        for (retry = 0; retry < adap->retries; retry++) {
 
@@ -1129,6 +1130,7 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
        dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02x\n",
                readl(i2c->regs + S3C2410_IICCON));
 
+       i2c->need_hw_init = 0;
        return 0;
 }
 
@@ -1160,6 +1162,27 @@ s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
 }
 #endif
 
+#ifdef CONFIG_CPU_IDLE
+static int s3c24xx_i2c_notifier(struct notifier_block *self,
+                               unsigned long cmd, void *v)
+{
+       struct s3c24xx_i2c *i2c;
+
+       switch (cmd) {
+       case LPA_EXIT:
+               list_for_each_entry(i2c, &drvdata_list, node)
+                       i2c->need_hw_init = 1;
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block s3c24xx_i2c_notifier_block = {
+       .notifier_call = s3c24xx_i2c_notifier,
+};
+#endif /*CONFIG_CPU_IDLE */
+
 /* s3c24xx_i2c_probe
  *
  * called by the bus driver when a suitable device is found
@@ -1247,17 +1270,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       /* initialise the i2c controller */
+       i2c->need_hw_init = 1;
 
-       if (!(i2c->quirks & QUIRK_FIMC_I2C)) {
-               clk_prepare_enable(i2c->clk);
-               ret = s3c24xx_i2c_init(i2c);
-               clk_disable_unprepare(i2c->clk);
-               if (ret != 0) {
-                       dev_err(&pdev->dev, "I2C controller init failed\n");
-                       return ret;
-               }
-       }
        /* find the IRQ for this unit (note, this relies on the init call to
         * ensure no current IRQs pending
         */
@@ -1303,6 +1317,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
 
        pm_runtime_enable(&i2c->adap.dev);
 
+       list_add_tail(&i2c->node, &drvdata_list);
+
        dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
        return 0;
 }
@@ -1345,11 +1361,7 @@ static int s3c24xx_i2c_resume_noirq(struct device *dev)
        int ret;
 
        i2c->suspended = 0;
-       if (!(i2c->quirks & QUIRK_FIMC_I2C)) {
-               clk_prepare_enable(i2c->clk);
-               s3c24xx_i2c_init(i2c);
-               clk_disable_unprepare(i2c->clk);
-       }
+       i2c->need_hw_init = 1;
 
        return 0;
 }
@@ -1361,11 +1373,8 @@ static int s3c24xx_i2c_runtime_resume(struct device *dev)
        struct platform_device *pdev = to_platform_device(dev);
        struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
 
-       if (i2c->quirks & QUIRK_FIMC_I2C) {
-               clk_prepare_enable(i2c->clk);
-               s3c24xx_i2c_init(i2c);
-               clk_disable_unprepare(i2c->clk);
-       }
+       if (i2c->quirks & QUIRK_FIMC_I2C)
+               i2c->need_hw_init = 1;
 
        return 0;
 }
@@ -1406,6 +1415,9 @@ static struct platform_driver s3c24xx_i2c_driver = {
 
 static int __init i2c_adap_s3c_init(void)
 {
+#ifdef CONFIG_CPU_IDLE
+       exynos_pm_register_notifier(&s3c24xx_i2c_notifier_block);
+#endif
        return platform_driver_register(&s3c24xx_i2c_driver);
 }
 subsys_initcall(i2c_adap_s3c_init);