diff options
author | Paul Walmsley <paul@pwsan.com> | 2008-11-21 21:39:55 (GMT) |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2008-11-21 21:39:55 (GMT) |
commit | fdd07fe6f6fe54250d8b1126b42ebdc72d938f05 (patch) | |
tree | 9f52a8091681f4c90eac953d5daacc378e6b2844 /drivers/i2c | |
parent | 9c76b878eb3f837ff98b37aa254e6cc7942e946b (diff) | |
download | linux-fsl-qoriq-fdd07fe6f6fe54250d8b1126b42ebdc72d938f05.tar.xz |
i2c-omap: reprogram OCP_SYSCONFIG register after reset
The I2C controller clears its OCP_SYSCONFIG register after an OCP soft reset.
Reprogram OCP_SYSCONFIG for maximum power savings on rev3.6 controllers
and beyond. On 2430, this involves setting the module AUTOIDLE bit.
On 3430, this includes module AUTOIDLE, wakeup enable, slave smart-idle,
and considers only the module functional clock state for idle-ack.
Boot-tested on 2430SDP and 3430SDP.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Richard Woodruff <r-woodruff2@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 40 |
1 files changed, 34 insertions, 6 deletions
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 3ac510d..b202354 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -123,11 +123,19 @@ #define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */ #endif -/* I2C System Status register (OMAP_I2C_SYSS): */ -#define OMAP_I2C_SYSS_RDONE (1 << 0) /* Reset Done */ +/* OCP_SYSSTATUS bit definitions */ +#define SYSS_RESETDONE_MASK (1 << 0) + +/* OCP_SYSCONFIG bit definitions */ +#define SYSC_CLOCKACTIVITY_MASK (0x3 << 8) +#define SYSC_SIDLEMODE_MASK (0x3 << 3) +#define SYSC_ENAWAKEUP_MASK (1 << 2) +#define SYSC_SOFTRESET_MASK (1 << 1) +#define SYSC_AUTOIDLE_MASK (1 << 0) + +#define SYSC_IDLEMODE_SMART 0x2 +#define SYSC_CLOCKACTIVITY_FCLK 0x2 -/* I2C System Configuration Register (OMAP_I2C_SYSC): */ -#define OMAP_I2C_SYSC_SRST (1 << 1) /* Soft Reset */ struct omap_i2c_dev { struct device *dev; @@ -239,13 +247,13 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) unsigned long internal_clk = 0; if (dev->rev >= OMAP_I2C_REV_2) { - omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, OMAP_I2C_SYSC_SRST); + omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_SOFTRESET_MASK); /* For some reason we need to set the EN bit before the * reset done bit gets set. */ timeout = jiffies + OMAP_I2C_TIMEOUT; omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); while (!(omap_i2c_read_reg(dev, OMAP_I2C_SYSS_REG) & - OMAP_I2C_SYSS_RDONE)) { + SYSS_RESETDONE_MASK)) { if (time_after(jiffies, timeout)) { dev_warn(dev->dev, "timeout waiting " "for controller reset\n"); @@ -253,6 +261,26 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) } msleep(1); } + + /* SYSC register is cleared by the reset; rewrite it */ + if (dev->rev == OMAP_I2C_REV_ON_2430) { + + omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, + SYSC_AUTOIDLE_MASK); + + } else if (dev->rev >= OMAP_I2C_REV_ON_3430) { + u32 v; + + v = SYSC_AUTOIDLE_MASK; + v |= SYSC_ENAWAKEUP_MASK; + v |= (SYSC_IDLEMODE_SMART << + __ffs(SYSC_SIDLEMODE_MASK)); + v |= (SYSC_CLOCKACTIVITY_FCLK << + __ffs(SYSC_CLOCKACTIVITY_MASK)); + + omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, v); + + } } omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); |