#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
};
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;
* 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)
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++) {
dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02x\n",
readl(i2c->regs + S3C2410_IICCON));
+ i2c->need_hw_init = 0;
return 0;
}
}
#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
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
*/
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;
}
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;
}
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;
}
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);