From patchwork Wed Jan 6 11:33:35 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philby John X-Patchwork-Id: 71270 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 o06BZYRY016642 for ; Wed, 6 Jan 2010 11:35:34 GMT Received: from dlep34.itg.ti.com ([157.170.170.115]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id o06BXa4e028359 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 6 Jan 2010 05:33:36 -0600 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep34.itg.ti.com (8.13.7/8.13.7) with ESMTP id o06BXZi7029954; Wed, 6 Jan 2010 05:33:35 -0600 (CST) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id 86F3280627; Wed, 6 Jan 2010 05:33:35 -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 7BBCE80626 for ; Wed, 6 Jan 2010 05:33:34 -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 o06BXY8H004071 for ; Wed, 6 Jan 2010 05:33:34 -0600 (CST) Received: from psmtp.com (na3sys009amx219.postini.com [74.125.149.59]) by medina.ext.ti.com (8.13.7/8.13.7) with SMTP id o06BXWaj012383 for ; Wed, 6 Jan 2010 05:33:33 -0600 Received: from source ([206.112.117.35]) by na3sys009amx219.postini.com ([74.125.148.10]) with SMTP; Wed, 06 Jan 2010 03:33:33 PST Received: from [10.161.2.200] (unknown [10.161.2.200]) by imap.sh.mvista.com (Postfix) with SMTP id 0E9023EC9 for ; Wed, 6 Jan 2010 03:33:29 -0800 (PST) Subject: [PATCH v2] i2c: Davinci i2c bus recovery procedure to clear the bus From: Philby John To: "davinci-linux-open-source@linux.davincidsp.com" Organization: MontaVista Date: Wed, 06 Jan 2010 17:03:35 +0530 Message-Id: <1262777615.3581.16.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:62.02581/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] 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@linux.davincidsp.com Errors-To: davinci-linux-open-source-bounces@linux.davincidsp.com diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index a9b650d..a20b2de 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -111,6 +111,8 @@ static struct platform_device davinci_nand_device = { static struct davinci_i2c_platform_data i2c_pdata = { .bus_freq = 400 /* kHz */, .bus_delay = 0 /* usec */, + .sda_pin = 15, + .scl_pin = 14, }; static struct snd_platform_data dm355_evm_snd_data; diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index fd0398b..b5ce36b 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -628,6 +628,8 @@ static struct i2c_board_info __initdata i2c_info[] = { static struct davinci_i2c_platform_data i2c_pdata = { .bus_freq = 20 /* kHz */, .bus_delay = 100 /* usec */, + .sda_pin = 44, + .scl_pin = 43, }; static void __init evm_init_i2c(void) diff --git a/arch/arm/mach-davinci/include/mach/i2c.h b/arch/arm/mach-davinci/include/mach/i2c.h index c248e9b..21be118 100644 --- a/arch/arm/mach-davinci/include/mach/i2c.h +++ b/arch/arm/mach-davinci/include/mach/i2c.h @@ -16,6 +16,8 @@ struct davinci_i2c_platform_data { unsigned int bus_freq; /* standard bus frequency (kHz) */ unsigned int bus_delay; /* post-transaction delay (usec) */ + unsigned int sda_pin; /* GPIO pin ID to use for SDA */ + unsigned int scl_pin; /* GPIO pin ID to use for SCL */ }; /* for board setup code */ diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 67d88cc..be18cab 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -35,6 +35,7 @@ #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 | \ @@ -134,6 +136,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); + 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 +261,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 +357,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;