aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses/i2c-omap.c
diff options
context:
space:
mode:
authorOleksandr Dmytryshyn <oleksandr.dmytryshyn@ti.com>2013-06-03 03:37:20 -0400
committerWolfram Sang <wsa@the-dreams.de>2013-06-19 06:04:26 -0400
commit4368de19ed3f67168d714ab34b5b27c6a0ebad4e (patch)
tree22a1be02632584787c5dec436758a8ff0a5d1751 /drivers/i2c/busses/i2c-omap.c
parent7a10f4732972b48f75a547a42f9cdfef340124a6 (diff)
i2c: omap: correct usage of the interrupt enable register
We've been lucky not to have any interrupts fire during the suspend path, otherwise we would have unpredictable behaviour in the kernel. Based on the logic of the kernel code interrupts from i2c should be prohibited during suspend. Kernel writes 0 to the I2C_IE register in the omap_i2c_runtime_suspend() function. In the other side kernel writes saved interrupt flags to the I2C_IE register in omap_i2c_runtime_resume() function. I.e. interrupts should be disabled during suspend. This works for chips with version1 registers scheme. Interrupts are disabled during suspend. For chips with version2 scheme registers writting 0 to the I2C_IE register does nothing (because now the I2C_IRQENABLE_SET register is located at this address). This register is used to enable interrupts. For disabling interrupts I2C_IRQENABLE_CLR register should be used. Because the registers I2C_IRQENABLE_SET and I2C_IE have the same addresses, the interrupt enabling procedure is unchanged. I've checked that interrupts in the i2c controller are still enabled after writting 0 to the I2C_IRQENABLE_SET register. With this patch interrupts are disabled in the omap_i2c_runtime_suspend() function. Patch is based on: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git tag: v3.10-rc2 Verified on OMAP4430. Signed-off-by: Oleksandr Dmytryshyn <oleksandr.dmytryshyn@ti.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c/busses/i2c-omap.c')
-rw-r--r--drivers/i2c/busses/i2c-omap.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 352f3c38d1f7..142b694d1c60 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -180,6 +180,8 @@ enum {
180#define I2C_OMAP_ERRATA_I207 (1 << 0) 180#define I2C_OMAP_ERRATA_I207 (1 << 0)
181#define I2C_OMAP_ERRATA_I462 (1 << 1) 181#define I2C_OMAP_ERRATA_I462 (1 << 1)
182 182
183#define OMAP_I2C_IP_V2_INTERRUPTS_MASK 0x6FFF
184
183struct omap_i2c_dev { 185struct omap_i2c_dev {
184 spinlock_t lock; /* IRQ synchronization */ 186 spinlock_t lock; /* IRQ synchronization */
185 struct device *dev; 187 struct device *dev;
@@ -193,6 +195,7 @@ struct omap_i2c_dev {
193 long latency); 195 long latency);
194 u32 speed; /* Speed of bus in kHz */ 196 u32 speed; /* Speed of bus in kHz */
195 u32 flags; 197 u32 flags;
198 u16 scheme;
196 u16 cmd_err; 199 u16 cmd_err;
197 u8 *buf; 200 u8 *buf;
198 u8 *regs; 201 u8 *regs;
@@ -1082,7 +1085,7 @@ omap_i2c_probe(struct platform_device *pdev)
1082 int irq; 1085 int irq;
1083 int r; 1086 int r;
1084 u32 rev; 1087 u32 rev;
1085 u16 minor, major, scheme; 1088 u16 minor, major;
1086 1089
1087 irq = platform_get_irq(pdev, 0); 1090 irq = platform_get_irq(pdev, 0);
1088 if (irq < 0) { 1091 if (irq < 0) {
@@ -1153,8 +1156,8 @@ omap_i2c_probe(struct platform_device *pdev)
1153 */ 1156 */
1154 rev = __raw_readw(dev->base + 0x04); 1157 rev = __raw_readw(dev->base + 0x04);
1155 1158
1156 scheme = OMAP_I2C_SCHEME(rev); 1159 dev->scheme = OMAP_I2C_SCHEME(rev);
1157 switch (scheme) { 1160 switch (dev->scheme) {
1158 case OMAP_I2C_SCHEME_0: 1161 case OMAP_I2C_SCHEME_0:
1159 dev->regs = (u8 *)reg_map_ip_v1; 1162 dev->regs = (u8 *)reg_map_ip_v1;
1160 dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG); 1163 dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG);
@@ -1283,7 +1286,11 @@ static int omap_i2c_runtime_suspend(struct device *dev)
1283 1286
1284 _dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG); 1287 _dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG);
1285 1288
1286 omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0); 1289 if (_dev->scheme == OMAP_I2C_SCHEME_0)
1290 omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0);
1291 else
1292 omap_i2c_write_reg(_dev, OMAP_I2C_IP_V2_IRQENABLE_CLR,
1293 OMAP_I2C_IP_V2_INTERRUPTS_MASK);
1287 1294
1288 if (_dev->rev < OMAP_I2C_OMAP1_REV_2) { 1295 if (_dev->rev < OMAP_I2C_OMAP1_REV_2) {
1289 omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */ 1296 omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */