From: Youngmin Nam Date: Thu, 2 Jul 2015 12:11:13 +0000 (+0900) Subject: i2c: s3c2410: add the new h/w init sequence X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=d2a72e08534957018e09516086ea368ea64a2c39;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git i2c: s3c2410: add the new h/w init sequence To recover from "cannot get bus (error -110)" error, add the new h/w init sequence. This init sequence initialize i2c bus (sda and scl), through clearing S3C2410_IICSTAT_TXRXEN. Change-Id: Id76af5a3c4baa18685b3104095fa3eb36942349f Signed-off-by: Hyunki Koo Signed-off-by: Youngmin Nam --- diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 3e5d67b0a7f4..e31b73e63398 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -93,6 +93,10 @@ static LIST_HEAD(drvdata_list); #define S3C2440_IICINT_BUSHOLD_CLEAR (1 << 8) +#define S3C2410_NEED_REG_INIT (1 << 0) +#define S3C2410_NEED_BUS_INIT (2 << 0) +#define S3C2410_NEED_FULL_INIT (3 << 0) + /* Treat S3C2410 as baseline hardware, anything else is supported via quirks */ #define QUIRK_S3C2440 (1 << 0) #define QUIRK_HDMIPHY (1 << 1) @@ -780,6 +784,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, ret = s3c24xx_i2c_set_master(i2c); if (ret != 0) { dev_err(i2c->dev, "cannot get bus (error %d)\n", ret); + i2c->need_hw_init = S3C2410_NEED_FULL_INIT; ret = -EAGAIN; goto out; } @@ -847,11 +852,12 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, if (ret) return ret; - if (i2c->need_hw_init) - s3c24xx_i2c_init(i2c); for (retry = 0; retry < adap->retries; retry++) { + if (i2c->need_hw_init & S3C2410_NEED_FULL_INIT) + s3c24xx_i2c_init(i2c); + ret = s3c24xx_i2c_doxfer(i2c, msgs, num); if (ret != -EAGAIN) { @@ -1057,14 +1063,20 @@ static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c) static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) { struct s3c2410_platform_i2c *pdata; + unsigned long iicstat = readl(i2c->regs + S3C2410_IICSTAT); unsigned int freq; /* get the plafrom data */ pdata = i2c->pdata; - /* write slave address */ + if (i2c->need_hw_init & S3C2410_NEED_BUS_INIT) { + /* reset i2c bus to recover from "cannot get bus" */ + iicstat &= ~S3C2410_IICSTAT_TXRXEN; + writel(iicstat, i2c->regs + S3C2410_IICSTAT); + } + /* write slave address */ writeb(pdata->slave_addr, i2c->regs + S3C2410_IICADD); dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr); @@ -1126,7 +1138,7 @@ static int s3c24xx_i2c_notifier(struct notifier_block *self, switch (cmd) { case LPA_EXIT: list_for_each_entry(i2c, &drvdata_list, node) - i2c->need_hw_init = 1; + i2c->need_hw_init = S3C2410_NEED_REG_INIT; break; } @@ -1225,7 +1237,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) return -EINVAL; } - i2c->need_hw_init = 1; + i2c->need_hw_init = S3C2410_NEED_REG_INIT; /* find the IRQ for this unit (note, this relies on the init call to * ensure no current IRQs pending @@ -1318,7 +1330,7 @@ static int s3c24xx_i2c_resume_noirq(struct device *dev) int ret; i2c->suspended = 0; - i2c->need_hw_init = 1; + i2c->need_hw_init = S3C2410_NEED_REG_INIT; return 0; } @@ -1331,7 +1343,7 @@ static int s3c24xx_i2c_runtime_resume(struct device *dev) struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); if (i2c->quirks & QUIRK_FIMC_I2C) - i2c->need_hw_init = 1; + i2c->need_hw_init = S3C2410_NEED_REG_INIT; return 0; }