diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-omap.c')
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 160 |
1 files changed, 81 insertions, 79 deletions
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 801df6000e9..6849635b268 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -49,8 +49,8 @@ /* I2C controller revisions present on specific hardware */ #define OMAP_I2C_REV_ON_2430 0x36 -#define OMAP_I2C_REV_ON_3430 0x3C -#define OMAP_I2C_REV_ON_3530_4430 0x40 +#define OMAP_I2C_REV_ON_3430_3530 0x3C +#define OMAP_I2C_REV_ON_3630_4430 0x40 /* timeout waiting for the controller to respond */ #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) @@ -173,7 +173,7 @@ enum { /* Errata definitions */ #define I2C_OMAP_ERRATA_I207 (1 << 0) -#define I2C_OMAP3_1P153 (1 << 1) +#define I2C_OMAP_ERRATA_I462 (1 << 1) struct omap_i2c_dev { struct device *dev; @@ -269,47 +269,6 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg) (i2c_dev->regs[reg] << i2c_dev->reg_shift)); } -static void omap_i2c_unidle(struct omap_i2c_dev *dev) -{ - if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); - omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate); - omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate); - omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate); - omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, dev->bufstate); - omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, dev->syscstate); - omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate); - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); - } - - /* - * Don't write to this register if the IE state is 0 as it can - * cause deadlock. - */ - if (dev->iestate) - omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate); -} - -static void omap_i2c_idle(struct omap_i2c_dev *dev) -{ - u16 iv; - - dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); - if (dev->dtrev == OMAP_I2C_IP_VERSION_2) - omap_i2c_write_reg(dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, 1); - else - omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0); - - if (dev->rev < OMAP_I2C_OMAP1_REV_2) { - iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */ - } else { - omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate); - - /* Flush posted write */ - omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); - } -} - static int omap_i2c_init(struct omap_i2c_dev *dev) { u16 psc = 0, scll = 0, sclh = 0, buf = 0; @@ -346,7 +305,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_AUTOIDLE_MASK); - } else if (dev->rev >= OMAP_I2C_REV_ON_3430) { + } else if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) { dev->syscstate = SYSC_AUTOIDLE_MASK; dev->syscstate |= SYSC_ENAWAKEUP_MASK; dev->syscstate |= (SYSC_IDLEMODE_SMART << @@ -468,11 +427,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) /* Take the I2C module out of reset: */ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); - dev->errata = 0; - - if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) - dev->errata |= I2C_OMAP_ERRATA_I207; - /* Enable interrupts */ dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK | @@ -514,7 +468,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) { struct omap_i2c_dev *dev = i2c_get_adapdata(adap); - int r; + unsigned long timeout; u16 w; dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", @@ -536,7 +490,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR; omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w); - init_completion(&dev->cmd_complete); + INIT_COMPLETION(dev->cmd_complete); dev->cmd_err = 0; w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; @@ -545,6 +499,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, if (dev->speed > 400) w |= OMAP_I2C_CON_OPMODE_HS; + if (msg->flags & I2C_M_STOP) + stop = 1; if (msg->flags & I2C_M_TEN) w |= OMAP_I2C_CON_XA; if (!(msg->flags & I2C_M_RD)) @@ -582,12 +538,10 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, * REVISIT: We should abort the transfer on signals, but the bus goes * into arbitration and we're currently unable to recover from it. */ - r = wait_for_completion_timeout(&dev->cmd_complete, - OMAP_I2C_TIMEOUT); + timeout = wait_for_completion_timeout(&dev->cmd_complete, + OMAP_I2C_TIMEOUT); dev->buf_len = 0; - if (r < 0) - return r; - if (r == 0) { + if (timeout == 0) { dev_err(dev->dev, "controller timed out\n"); omap_i2c_init(dev); return -ETIMEDOUT; @@ -628,7 +582,9 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) int i; int r; - pm_runtime_get_sync(dev->dev); + r = pm_runtime_get_sync(dev->dev); + if (IS_ERR_VALUE(r)) + return r; r = omap_i2c_wait_for_bb(dev); if (r < 0) @@ -658,7 +614,8 @@ out: static u32 omap_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | + I2C_FUNC_PROTOCOL_MANGLING; } static inline void @@ -764,11 +721,11 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id) #endif /* - * OMAP3430 Errata 1.153: When an XRDY/XDR is hit, wait for XUDF before writing + * OMAP3430 Errata i462: When an XRDY/XDR is hit, wait for XUDF before writing * data to DATA_REG. Otherwise some data bytes can be lost while transferring * them from the memory to the I2C interface. */ -static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err) +static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err) { unsigned long timeout = 10000; @@ -776,7 +733,6 @@ static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err) if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); - *err |= OMAP_I2C_STAT_XUDF; return -ETIMEDOUT; } @@ -789,6 +745,7 @@ static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err) return 0; } + *err |= OMAP_I2C_STAT_XUDF; return 0; } @@ -927,8 +884,8 @@ complete: break; } - if ((dev->errata & I2C_OMAP3_1P153) && - errata_omap3_1p153(dev, &stat, &err)) + if ((dev->errata & I2C_OMAP_ERRATA_I462) && + errata_omap3_i462(dev, &stat, &err)) goto complete; omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); @@ -1045,6 +1002,7 @@ omap_i2c_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, dev); + init_completion(&dev->cmd_complete); dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; @@ -1054,12 +1012,19 @@ omap_i2c_probe(struct platform_device *pdev) dev->regs = (u8 *)reg_map_ip_v1; pm_runtime_enable(dev->dev); - pm_runtime_get_sync(dev->dev); + r = pm_runtime_get_sync(dev->dev); + if (IS_ERR_VALUE(r)) + goto err_free_mem; dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff; - if (dev->rev <= OMAP_I2C_REV_ON_3430) - dev->errata |= I2C_OMAP3_1P153; + dev->errata = 0; + + if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) + dev->errata |= I2C_OMAP_ERRATA_I207; + + if (dev->rev <= OMAP_I2C_REV_ON_3430_3530) + dev->errata |= I2C_OMAP_ERRATA_I462; if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) { u16 s; @@ -1076,7 +1041,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->fifo_size = (dev->fifo_size / 2); - if (dev->rev >= OMAP_I2C_REV_ON_3530_4430) + if (dev->rev >= OMAP_I2C_REV_ON_3630_4430) dev->b_hw = 0; /* Disable hardware fixes */ else dev->b_hw = 1; /* Enable hardware fixes */ @@ -1092,7 +1057,7 @@ omap_i2c_probe(struct platform_device *pdev) isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr : omap_i2c_isr; - r = request_irq(dev->irq, isr, 0, pdev->name, dev); + r = request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev); if (r) { dev_err(dev->dev, "failure requesting irq %i\n", dev->irq); @@ -1102,8 +1067,6 @@ omap_i2c_probe(struct platform_device *pdev) dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id, dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed); - pm_runtime_put(dev->dev); - adap = &dev->adapter; i2c_set_adapdata(adap, dev); adap->owner = THIS_MODULE; @@ -1123,6 +1086,8 @@ omap_i2c_probe(struct platform_device *pdev) of_i2c_register_devices(adap); + pm_runtime_put(dev->dev); + return 0; err_free_irq: @@ -1131,6 +1096,7 @@ err_unuse_clocks: omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); pm_runtime_put(dev->dev); iounmap(dev->base); + pm_runtime_disable(&pdev->dev); err_free_mem: platform_set_drvdata(pdev, NULL); kfree(dev); @@ -1140,17 +1106,23 @@ err_release_region: return r; } -static int -omap_i2c_remove(struct platform_device *pdev) +static int __devexit omap_i2c_remove(struct platform_device *pdev) { struct omap_i2c_dev *dev = platform_get_drvdata(pdev); struct resource *mem; + int ret; platform_set_drvdata(pdev, NULL); free_irq(dev->irq, dev); i2c_del_adapter(&dev->adapter); + ret = pm_runtime_get_sync(&pdev->dev); + if (IS_ERR_VALUE(ret)) + return ret; + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); iounmap(dev->base); kfree(dev); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1158,13 +1130,26 @@ omap_i2c_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM #ifdef CONFIG_PM_RUNTIME static int omap_i2c_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct omap_i2c_dev *_dev = platform_get_drvdata(pdev); + u16 iv; + + _dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG); + + omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0); - omap_i2c_idle(_dev); + if (_dev->rev < OMAP_I2C_OMAP1_REV_2) { + iv = omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */ + } else { + omap_i2c_write_reg(_dev, OMAP_I2C_STAT_REG, _dev->iestate); + + /* Flush posted write */ + omap_i2c_read_reg(_dev, OMAP_I2C_STAT_REG); + } return 0; } @@ -1174,23 +1159,40 @@ static int omap_i2c_runtime_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct omap_i2c_dev *_dev = platform_get_drvdata(pdev); - omap_i2c_unidle(_dev); + if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { + omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, 0); + omap_i2c_write_reg(_dev, OMAP_I2C_PSC_REG, _dev->pscstate); + omap_i2c_write_reg(_dev, OMAP_I2C_SCLL_REG, _dev->scllstate); + omap_i2c_write_reg(_dev, OMAP_I2C_SCLH_REG, _dev->sclhstate); + omap_i2c_write_reg(_dev, OMAP_I2C_BUF_REG, _dev->bufstate); + omap_i2c_write_reg(_dev, OMAP_I2C_SYSC_REG, _dev->syscstate); + omap_i2c_write_reg(_dev, OMAP_I2C_WE_REG, _dev->westate); + omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + } + + /* + * Don't write to this register if the IE state is 0 as it can + * cause deadlock. + */ + if (_dev->iestate) + omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, _dev->iestate); return 0; } +#endif /* CONFIG_PM_RUNTIME */ static struct dev_pm_ops omap_i2c_pm_ops = { - .runtime_suspend = omap_i2c_runtime_suspend, - .runtime_resume = omap_i2c_runtime_resume, + SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend, + omap_i2c_runtime_resume, NULL) }; #define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops) #else #define OMAP_I2C_PM_OPS NULL -#endif +#endif /* CONFIG_PM */ static struct platform_driver omap_i2c_driver = { .probe = omap_i2c_probe, - .remove = omap_i2c_remove, + .remove = __devexit_p(omap_i2c_remove), .driver = { .name = "omap_i2c", .owner = THIS_MODULE, |