From patchwork Fri Apr 1 07:16:29 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heiko Schocher X-Patchwork-Id: 89223 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id A292BB6F8D for ; Fri, 1 Apr 2011 18:25:21 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 8E22928151; Fri, 1 Apr 2011 09:24:21 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id eDRgbP8QMOyQ; Fri, 1 Apr 2011 09:24:21 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id AFF15280D6; Fri, 1 Apr 2011 09:23:23 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 7D79328087 for ; Fri, 1 Apr 2011 09:23:15 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id YJ+OmF2vo91n for ; Fri, 1 Apr 2011 09:23:15 +0200 (CEST) X-policyd-weight: IN_SBL_XBL_SPAMHAUS=4.35 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from pollux.denx.de (p4FF073FC.dip.t-dialin.net [79.240.115.252]) by theia.denx.de (Postfix) with ESMTP id 8B0E628090 for ; Fri, 1 Apr 2011 09:23:09 +0200 (CEST) Received: by pollux.denx.de (Postfix, from userid 515) id A89D818015830; Fri, 1 Apr 2011 09:16:38 +0200 (CEST) From: Heiko Schocher To: u-boot@lists.denx.de Date: Fri, 1 Apr 2011 09:16:29 +0200 Message-Id: <1301642195-15280-18-git-send-email-hs@denx.de> X-Mailer: git-send-email 1.7.4 In-Reply-To: <1301642195-15280-1-git-send-email-hs@denx.de> References: <1299591018-8944-1-git-send-email-hs@denx.de> <1301642195-15280-1-git-send-email-hs@denx.de> In-Reply-To: <1299591018-8944-1-git-send-email-hs@denx.de> References: <1299591018-8944-1-git-send-email-hs@denx.de> Cc: Valentin Longchamp , Holger Brunck , Heiko Schocher Subject: [U-Boot] [PATCH v4 17/23] keymile, common; fix i2c deblocking support X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.9 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de This patch fix the i2c deblocking facility with the i2c HW-Controller. The required delays for byte reading, the enhanced criteria for stop the dummy read and required 5 start/stop sequences are added. Add i2c deblocking before ivm eeprom read. Improve i2c deblocking sequence by respecting stop hold time. Cleaned function for deblocking. Have now one function i2c_make_abort() available for bitbang, mpc82xx and mpc83xx harware controller. Signed-off-by: Stefan Bigler Signed-off-by: Holger Brunck Signed-off-by: Heiko Schocher cc: Valentin Longchamp --- Changes for v2: - fix checkpatch.pl errors and warnings Changes for v3: - rebased only board/keymile/common/common.c | 121 ++++++++++++++++++++++++++++++----------- 1 files changed, 89 insertions(+), 32 deletions(-) diff --git a/board/keymile/common/common.c b/board/keymile/common/common.c index 2d0aee9..6600e08 100644 --- a/board/keymile/common/common.c +++ b/board/keymile/common/common.c @@ -40,6 +40,9 @@ #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) #include +static void i2c_write_start_seq(void); +static int i2c_make_abort(void); + int ivm_calc_crc(unsigned char *buf, int len) { const unsigned short crc_tab[16] = { @@ -329,8 +332,11 @@ int ivm_read_eeprom(void) if (buf != NULL) dev_addr = simple_strtoul((char *)buf, NULL, 16); + /* add deblocking here */ + i2c_make_abort(); + ret = i2c_read(dev_addr, 0, 1, i2c_buffer, - CONFIG_SYS_IVM_EEPROM_MAX_LEN); + CONFIG_SYS_IVM_EEPROM_MAX_LEN); if (ret != 0) { printf ("Error reading EEprom\n"); return -2; @@ -340,7 +346,7 @@ int ivm_read_eeprom(void) } #if defined(CONFIG_SYS_I2C_INIT_BOARD) -#define DELAY_ABORT_SEQ 62 +#define DELAY_ABORT_SEQ 62 /* @200kHz 9 clocks = 44us, 62us is ok */ #define DELAY_HALF_PERIOD (500 / (CONFIG_SYS_I2C_SPEED / 1000)) #if defined(CONFIG_MGCOGE) || defined(CONFIG_MGCOGE2NE) @@ -404,7 +410,7 @@ static void setports(int gpio) #endif #if !defined(CONFIG_MPC83xx) -static void writeStartSeq(void) +static void i2c_write_start_seq(void) { set_sda(1); udelay(DELAY_HALF_PERIOD); @@ -426,6 +432,21 @@ static void writeStartSeq(void) */ static int i2c_make_abort(void) { + +#if defined(CONFIG_HARD_I2C) && !defined(MACH_TYPE_KM_KIRKWOOD) + immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ; + i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c; + + /* + * disable I2C controller first, otherwhise it thinks we want to + * talk to the slave port... + */ + clrbits_8(&i2c->i2c_i2mod, 0x01); + + /* Set the PortPins to GPIO */ + setports(1); +#endif + int scl_state = 0; int sda_state = 0; int i = 0; @@ -449,57 +470,93 @@ static int i2c_make_abort(void) } if (ret == 0) for (i = 0; i < 5; i++) - writeStartSeq(); + i2c_write_start_seq(); + /* respect stop setup time */ + udelay(DELAY_ABORT_SEQ); + set_scl(1); + udelay(DELAY_ABORT_SEQ); + set_sda(1); get_sda(); + +#if defined(CONFIG_HARD_I2C) + /* Set the PortPins back to use for I2C */ + setports(0); +#endif return ret; } #endif -/* - * i2c_init_board - reset i2c bus. When the board is powercycled during a - * bus transfer it might hang; for details see doc/I2C_Edge_Conditions. - */ -void i2c_init_board(void) -{ #if defined(CONFIG_MPC83xx) +static void i2c_write_start_seq(void) +{ + struct fsl_i2c *dev; + dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET); + udelay(DELAY_ABORT_SEQ); + out_8(&dev->cr, (I2C_CR_MEN | I2C_CR_MSTA)); + udelay(DELAY_ABORT_SEQ); + out_8(&dev->cr, (I2C_CR_MEN)); +} + +static int i2c_make_abort(void) +{ struct fsl_i2c *dev; dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET); uchar dummy; + uchar last; + int nbr_read = 0; + int i = 0; + int ret = 0; + /* wait after each operation to finsh with a delay */ out_8(&dev->cr, (I2C_CR_MSTA)); + udelay(DELAY_ABORT_SEQ); out_8(&dev->cr, (I2C_CR_MEN | I2C_CR_MSTA)); + udelay(DELAY_ABORT_SEQ); dummy = in_8(&dev->dr); - dummy = in_8(&dev->dr); - if (dummy != 0xff) { - dummy = in_8(&dev->dr); - } - out_8(&dev->cr, (I2C_CR_MEN)); - out_8(&dev->cr, 0x00); - out_8(&dev->cr, (I2C_CR_MEN)); -#else -#if defined(CONFIG_HARD_I2C) && !defined(MACH_TYPE_KM_KIRKWOOD) - immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ; - i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c; + udelay(DELAY_ABORT_SEQ); + last = in_8(&dev->dr); + nbr_read++; /* - * disable I2C controller first, otherwhise it thinks we want to - * talk to the slave port... + * do read until the last bit is 1, but stop if the full eeprom is + * read. */ - clrbits_8(&i2c->i2c_i2mod, 0x01); + while (((last & 0x01) != 0x01) && + (nbr_read < CONFIG_SYS_IVM_EEPROM_MAX_LEN)) { + udelay(DELAY_ABORT_SEQ); + last = in_8(&dev->dr); + nbr_read++; + } + if ((last & 0x01) != 0x01) + ret = -2; + if ((last != 0xff) || (nbr_read > 1)) + printf("[INFO] i2c abort after %d bytes (0x%02x)\n", + nbr_read, last); + udelay(DELAY_ABORT_SEQ); + out_8(&dev->cr, (I2C_CR_MEN)); + udelay(DELAY_ABORT_SEQ); + /* clear status reg */ + out_8(&dev->sr, 0); - /* Set the PortPins to GPIO */ - setports(1); + for (i = 0; i < 5; i++) + i2c_write_start_seq(); + if (ret != 0) + printf("[ERROR] i2c abort failed after %d bytes (0x%02x)\n", + nbr_read, last); + + return ret; +} #endif +/** + * i2c_init_board - reset i2c bus. When the board is powercycled during a + * bus transfer it might hang; for details see doc/I2C_Edge_Conditions. + */ +void i2c_init_board(void) +{ /* Now run the AbortSequence() */ i2c_make_abort(); - -#if defined(CONFIG_HARD_I2C) - /* Set the PortPins back to use for I2C */ - setports(0); -#endif -#endif } #endif #endif