summaryrefslogtreecommitdiff
path: root/drivers/i2c/busses/i2c-s3c2410.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-04-09 08:45:40 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-09 08:45:40 -0700
commit39de65aa2c3eee901db020a4f1396998e09602a3 (patch)
tree0582450ec0b5b6b9778275b431207145d5fedfc8 /drivers/i2c/busses/i2c-s3c2410.c
parent97e18dc007546fce8e99098480b921a02ebb3037 (diff)
parent1fbeab0b8fd5e655ffef8a793b869eb7dffe0337 (diff)
Merge branch 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: "Here is the pull request from the i2c subsystem. It got a little delayed because I needed to wait for a dependency to be included (commit b424080a9e08: "reset: Add optional resets and stubs"). Plus, I had some email problems. All done now, the highlights are: - drivers can now deprecate their use of i2c classes. That shouldn't be used on embedded platforms anyhow and was often blindly copy&pasted. This mechanism gives users time to switch away and ultimately boot faster once the use of classes for those drivers is gone for good. - new drivers for QUP, Cadence, efm32 - tracepoint support for I2C and SMBus - bigger cleanups for the mv64xxx, nomadik, and designware drivers And the usual bugfixes, cleanups, feature additions. Most stuff has been in linux-next for a while. Just some hot fixes and new drivers were added a bit more recently." * 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (63 commits) i2c: cadence: fix Kconfig dependency i2c: Add driver for Cadence I2C controller i2c: cadence: Document device tree bindings Documentation: i2c: improve section about flags mangling the protocol i2c: qup: use proper type fro clk_freq i2c: qup: off by ones in qup_i2c_probe() i2c: efm32: fix binding doc MAINTAINERS: update I2C web resources i2c: qup: New bus driver for the Qualcomm QUP I2C controller i2c: qup: Add device tree bindings information i2c: i2c-xiic: deprecate class based instantiation i2c: i2c-sirf: deprecate class based instantiation i2c: i2c-mv64xxx: deprecate class based instantiation i2c: i2c-designware-platdrv: deprecate class based instantiation i2c: i2c-davinci: deprecate class based instantiation i2c: i2c-bcm2835: deprecate class based instantiation i2c: mv64xxx: Fix reset controller handling i2c: omap: fix usage of IS_ERR_VALUE with pm_runtime_get_sync i2c: efm32: new bus driver i2c: exynos5: remove unnecessary cast of void pointer ...
Diffstat (limited to 'drivers/i2c/busses/i2c-s3c2410.c')
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c39
1 files changed, 34 insertions, 5 deletions
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 684d21e71e4a..ae4491062e41 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -601,6 +601,31 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
return IRQ_HANDLED;
}
+/*
+ * Disable the bus so that we won't get any interrupts from now on, or try
+ * to drive any lines. This is the default state when we don't have
+ * anything to send/receive.
+ *
+ * If there is an event on the bus, or we have a pre-existing event at
+ * kernel boot time, we may not notice the event and the I2C controller
+ * will lock the bus with the I2C clock line low indefinitely.
+ */
+static inline void s3c24xx_i2c_disable_bus(struct s3c24xx_i2c *i2c)
+{
+ unsigned long tmp;
+
+ /* Stop driving the I2C pins */
+ tmp = readl(i2c->regs + S3C2410_IICSTAT);
+ tmp &= ~S3C2410_IICSTAT_TXRXEN;
+ writel(tmp, i2c->regs + S3C2410_IICSTAT);
+
+ /* We don't expect any interrupts now, and don't want send acks */
+ tmp = readl(i2c->regs + S3C2410_IICCON);
+ tmp &= ~(S3C2410_IICCON_IRQEN | S3C2410_IICCON_IRQPEND |
+ S3C2410_IICCON_ACKEN);
+ writel(tmp, i2c->regs + S3C2410_IICCON);
+}
+
/* s3c24xx_i2c_set_master
*
@@ -735,7 +760,11 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
s3c24xx_i2c_wait_idle(i2c);
+ s3c24xx_i2c_disable_bus(i2c);
+
out:
+ i2c->state = STATE_IDLE;
+
return ret;
}
@@ -1004,7 +1033,6 @@ static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
{
- unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN;
struct s3c2410_platform_i2c *pdata;
unsigned int freq;
@@ -1018,12 +1046,12 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);
- writel(iicon, i2c->regs + S3C2410_IICCON);
+ writel(0, i2c->regs + S3C2410_IICCON);
+ writel(0, i2c->regs + S3C2410_IICSTAT);
/* we need to work out the divisors for the clock... */
if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) {
- writel(0, i2c->regs + S3C2410_IICCON);
dev_err(i2c->dev, "cannot meet bus frequency required\n");
return -EINVAL;
}
@@ -1031,7 +1059,8 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
/* todo - check that the i2c lines aren't being dragged anywhere */
dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);
- dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon);
+ dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02x\n",
+ readl(i2c->regs + S3C2410_IICCON));
return 0;
}
@@ -1106,7 +1135,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
i2c->adap.owner = THIS_MODULE;
i2c->adap.algo = &s3c24xx_i2c_algorithm;
i2c->adap.retries = 2;
- i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
i2c->tx_setup = 50;
init_waitqueue_head(&i2c->wait);