@@ -35,6 +35,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/gpio.h>
#include <mach/hardware.h>
@@ -43,6 +44,7 @@
/* ----- global defines ----------------------------------------------- */
#define DAVINCI_I2C_TIMEOUT (1*HZ)
+#define DAVINCI_I2C_MAX_TRIES 2
#define I2C_DAVINCI_INTR_ALL (DAVINCI_I2C_IMR_AAS | \
DAVINCI_I2C_IMR_SCD | \
DAVINCI_I2C_IMR_ARDY | \
@@ -134,6 +136,38 @@ static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg)
return __raw_readw(i2c_dev->base + reg);
}
+/* Generate a pulse on the i2c clock pin. */
+static void pulse_i2c_clock(void)
+{
+ gpio_set_value(14, 0);
+ udelay(20);
+ gpio_set_value(14, 1);
+ udelay(20);
+}
+
+/* This routine does i2c bus recovery as specified in the
+ * i2c protocol Rev. 03 section 3.16 titled "Bus clear"
+ */
+static void i2c_recover_bus(struct davinci_i2c_dev *dev)
+{
+ u16 i;
+ u32 flag = 0;
+
+ dev_err(dev->dev, "initiating i2c bus recovery\n");
+ /* Send NACK to the slave */
+ flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ flag |= DAVINCI_I2C_MDR_NACK;
+ /* write the data into mode register */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+ /* Send high and low on the SCL line */
+ for (i = 0; i < 9; i++)
+ pulse_i2c_clock();
+ /* Send STOP */
+ flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ MOD_REG_BIT(flag, DAVINCI_I2C_MDR_STP, 1);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+}
+
/*
* This functions configures I2C and brings I2C out of reset.
* This function is called during I2C init function. This function
@@ -221,19 +255,26 @@ static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev,
char allow_sleep)
{
unsigned long timeout;
+ static u16 to_cnt = 0;
timeout = jiffies + dev->adapter.timeout;
while (davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG)
- & DAVINCI_I2C_STR_BB) {
- if (time_after(jiffies, timeout)) {
- dev_warn(dev->dev,
- "timeout waiting for bus ready\n");
- return -ETIMEDOUT;
+ & DAVINCI_I2C_STR_BB) {
+ if (to_cnt <= DAVINCI_I2C_MAX_TRIES) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev,
+ "timeout waiting for bus ready\n");
+ to_cnt++;
+ return -ETIMEDOUT;
+ } else {
+ to_cnt = 0;
+ i2c_recover_bus(dev);
+ i2c_davinci_init(dev);
+ }
}
if (allow_sleep)
schedule_timeout(1);
}
-
return 0;
}
@@ -310,6 +351,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
dev->adapter.timeout);
if (r == 0) {
dev_err(dev->dev, "controller timed out\n");
+ i2c_recover_bus(dev);
i2c_davinci_init(dev);
dev->buf_len = 0;
return -ETIMEDOUT;