From patchwork Tue Jan 12 11:17:16 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philby John X-Patchwork-Id: 72354 Received: from comal.ext.ti.com (comal.ext.ti.com [198.47.26.152]) by demeter.kernel.org (8.14.3/8.14.2) with ESMTP id o0CBHsId030630 for ; Tue, 12 Jan 2010 11:17:54 GMT Received: from dlep36.itg.ti.com ([157.170.170.91]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id o0CBHrcM022821 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 12 Jan 2010 05:17:53 -0600 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep36.itg.ti.com (8.13.8/8.13.8) with ESMTP id o0CBHroQ024101 for ; Tue, 12 Jan 2010 05:17:53 -0600 (CST) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id C58EB80687 for ; Tue, 12 Jan 2010 05:17:49 -0600 (CST) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dflp53.itg.ti.com (dflp53.itg.ti.com [128.247.5.6]) by linux.omap.com (Postfix) with ESMTP id 15FB880627 for ; Tue, 12 Jan 2010 05:17:25 -0600 (CST) Received: from medina.ext.ti.com (localhost [127.0.0.1]) by dflp53.itg.ti.com (8.13.8/8.13.8) with ESMTP id o0CBHOg9017393 for ; Tue, 12 Jan 2010 05:17:24 -0600 (CST) Received: from psmtp.com (na3sys009amx204.postini.com [74.125.149.44]) by medina.ext.ti.com (8.13.7/8.13.7) with SMTP id o0CBHONP017081 for ; Tue, 12 Jan 2010 05:17:24 -0600 Received: from source ([206.112.117.35]) by na3sys009amx204.postini.com ([74.125.148.10]) with SMTP; Tue, 12 Jan 2010 03:17:24 PST Received: from [10.161.2.200] (unknown [10.161.2.200]) by imap.sh.mvista.com (Postfix) with SMTP id 943EB3ECF; Tue, 12 Jan 2010 03:17:19 -0800 (PST) Subject: [PATCH v3 2/2] i2c: Davinci i2c bus recovery procedure to clear the bus From: Philby John To: linux-i2c@vger.kernel.org Organization: MontaVista Date: Tue, 12 Jan 2010 16:47:16 +0530 Message-Id: <1263295036.3437.17.camel@localhost.localdomain> Mime-Version: 1.0 X-Mailer: Evolution 2.24.5 (2.24.5-2.fc10) X-pstn-neptune: 0/0/0.00/0 X-pstn-levels: (S:52.64420/99.90000 CV:99.9000 FC:95.5390 LC:95.5390 R:95.9108 P:95.9108 M:97.0282 C:98.6951 ) X-pstn-settings: 2 (0.5000:0.5000) s cv gt3 gt2 gt1 X-pstn-addresses: from [db-null] Cc: "davinci-linux-open-source@linux.davincidsp.com" X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: davinci-linux-open-source-bounces+patchwork-davinci=patchwork.kernel.org@linux.davincidsp.com Errors-To: davinci-linux-open-source-bounces+patchwork-davinci=patchwork.kernel.org@linux.davincidsp.com diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 35f9daa..5459065 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -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 | \ @@ -130,6 +132,44 @@ 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 generic_i2c_clock_pulse(unsigned int scl_pin) +{ + u16 i; + + if (scl_pin) { + /* Send high and low on the SCL line */ + for (i = 0; i < 9; i++) { + gpio_set_value(scl_pin, 0); + udelay(20); + gpio_set_value(scl_pin, 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) +{ + u32 flag = 0; + struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; + + 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); + if (pdata) + generic_i2c_clock_pulse(pdata->scl_pin); + /* Send STOP */ + flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); + flag |= DAVINCI_I2C_MDR_STP; + davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); +} + static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev, int val) { @@ -235,14 +275,22 @@ static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev, char allow_sleep) { unsigned long timeout; + static u16 to_cnt; 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; + 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); @@ -324,6 +372,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;