summaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-pxa.c55
1 files changed, 39 insertions, 16 deletions
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 44d838410f1..8b38ed0379d 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -60,19 +60,21 @@ struct pxa_i2c {
u32 icrlog[32];
void __iomem *reg_base;
+ unsigned int reg_shift;
unsigned long iobase;
unsigned long iosize;
int irq;
- int use_pio;
+ unsigned int use_pio :1;
+ unsigned int fast_mode :1;
};
-#define _IBMR(i2c) ((i2c)->reg_base + 0)
-#define _IDBR(i2c) ((i2c)->reg_base + 8)
-#define _ICR(i2c) ((i2c)->reg_base + 0x10)
-#define _ISR(i2c) ((i2c)->reg_base + 0x18)
-#define _ISAR(i2c) ((i2c)->reg_base + 0x20)
+#define _IBMR(i2c) ((i2c)->reg_base + (0x0 << (i2c)->reg_shift))
+#define _IDBR(i2c) ((i2c)->reg_base + (0x4 << (i2c)->reg_shift))
+#define _ICR(i2c) ((i2c)->reg_base + (0x8 << (i2c)->reg_shift))
+#define _ISR(i2c) ((i2c)->reg_base + (0xc << (i2c)->reg_shift))
+#define _ISAR(i2c) ((i2c)->reg_base + (0x10 << (i2c)->reg_shift))
/*
* I2C Slave mode address
@@ -188,14 +190,14 @@ static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c)
static void i2c_pxa_abort(struct pxa_i2c *i2c)
{
- unsigned long timeout = jiffies + HZ/4;
+ int i = 250;
if (i2c_pxa_is_slavemode(i2c)) {
dev_dbg(&i2c->adap.dev, "%s: called in slave mode\n", __func__);
return;
}
- while (time_before(jiffies, timeout) && (readl(_IBMR(i2c)) & 0x1) == 0) {
+ while ((i > 0) && (readl(_IBMR(i2c)) & 0x1) == 0) {
unsigned long icr = readl(_ICR(i2c));
icr &= ~ICR_START;
@@ -205,7 +207,8 @@ static void i2c_pxa_abort(struct pxa_i2c *i2c)
show_state(i2c);
- msleep(1);
+ mdelay(1);
+ i --;
}
writel(readl(_ICR(i2c)) & ~(ICR_MA | ICR_START | ICR_STOP),
@@ -364,7 +367,7 @@ static void i2c_pxa_reset(struct pxa_i2c *i2c)
writel(i2c->slave_addr, _ISAR(i2c));
/* set control register values */
- writel(I2C_ICR_INIT, _ICR(i2c));
+ writel(I2C_ICR_INIT | (i2c->fast_mode ? ICR_FM : 0), _ICR(i2c));
#ifdef CONFIG_I2C_PXA_SLAVE
dev_info(&i2c->adap.dev, "Enabling slave mode\n");
@@ -907,12 +910,6 @@ static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num
struct pxa_i2c *i2c = adap->algo_data;
int ret, i;
- /* If the I2C controller is disabled we need to reset it (probably due
- to a suspend/resume destroying state). We do this here as we can then
- avoid worrying about resuming the controller before its users. */
- if (!(readl(_ICR(i2c)) & ICR_IUE))
- i2c_pxa_reset(i2c);
-
for (i = adap->retries; i >= 0; i--) {
ret = i2c_pxa_do_xfer(i2c, msgs, num);
if (ret != I2C_RETRY)
@@ -993,6 +990,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
ret = -EIO;
goto eremap;
}
+ i2c->reg_shift = (cpu_is_pxa3xx() && (dev->id == 1)) ? 0 : 1;
i2c->iobase = res->start;
i2c->iosize = res_len(res);
@@ -1013,6 +1011,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
if (plat) {
i2c->adap.class = plat->class;
i2c->use_pio = plat->use_pio;
+ i2c->fast_mode = plat->fast_mode;
}
if (i2c->use_pio) {
@@ -1082,9 +1081,33 @@ static int __exit i2c_pxa_remove(struct platform_device *dev)
return 0;
}
+#ifdef CONFIG_PM
+static int i2c_pxa_suspend_late(struct platform_device *dev, pm_message_t state)
+{
+ struct pxa_i2c *i2c = platform_get_drvdata(dev);
+ clk_disable(i2c->clk);
+ return 0;
+}
+
+static int i2c_pxa_resume_early(struct platform_device *dev)
+{
+ struct pxa_i2c *i2c = platform_get_drvdata(dev);
+
+ clk_enable(i2c->clk);
+ i2c_pxa_reset(i2c);
+
+ return 0;
+}
+#else
+#define i2c_pxa_suspend_late NULL
+#define i2c_pxa_resume_early NULL
+#endif
+
static struct platform_driver i2c_pxa_driver = {
.probe = i2c_pxa_probe,
.remove = __exit_p(i2c_pxa_remove),
+ .suspend_late = i2c_pxa_suspend_late,
+ .resume_early = i2c_pxa_resume_early,
.driver = {
.name = "pxa2xx-i2c",
.owner = THIS_MODULE,