提交 6c11aeaf 编写于 作者: H Heiko Schocher 提交者: Wolfgang Denk

keymile, common; fix i2c deblocking support

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: NStefan Bigler <stefan.bigler@keymile.com>
Signed-off-by: NHolger Brunck <holger.brunck@keymile.com>
Signed-off-by: NHeiko Schocher <hs@denx.de>
cc: Valentin Longchamp <valentin.longchamp@keymile.com>
上级 8ed74341
...@@ -40,6 +40,9 @@ ...@@ -40,6 +40,9 @@
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
#include <i2c.h> #include <i2c.h>
static void i2c_write_start_seq(void);
static int i2c_make_abort(void);
int ivm_calc_crc(unsigned char *buf, int len) int ivm_calc_crc(unsigned char *buf, int len)
{ {
const unsigned short crc_tab[16] = { const unsigned short crc_tab[16] = {
...@@ -329,8 +332,11 @@ int ivm_read_eeprom(void) ...@@ -329,8 +332,11 @@ int ivm_read_eeprom(void)
if (buf != NULL) if (buf != NULL)
dev_addr = simple_strtoul((char *)buf, NULL, 16); dev_addr = simple_strtoul((char *)buf, NULL, 16);
/* add deblocking here */
i2c_make_abort();
ret = i2c_read(dev_addr, 0, 1, i2c_buffer, ret = i2c_read(dev_addr, 0, 1, i2c_buffer,
CONFIG_SYS_IVM_EEPROM_MAX_LEN); CONFIG_SYS_IVM_EEPROM_MAX_LEN);
if (ret != 0) { if (ret != 0) {
printf ("Error reading EEprom\n"); printf ("Error reading EEprom\n");
return -2; return -2;
...@@ -340,7 +346,7 @@ int ivm_read_eeprom(void) ...@@ -340,7 +346,7 @@ int ivm_read_eeprom(void)
} }
#if defined(CONFIG_SYS_I2C_INIT_BOARD) #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)) #define DELAY_HALF_PERIOD (500 / (CONFIG_SYS_I2C_SPEED / 1000))
#if defined(CONFIG_MGCOGE) || defined(CONFIG_MGCOGE2NE) #if defined(CONFIG_MGCOGE) || defined(CONFIG_MGCOGE2NE)
...@@ -404,7 +410,7 @@ static void setports(int gpio) ...@@ -404,7 +410,7 @@ static void setports(int gpio)
#endif #endif
#if !defined(CONFIG_MPC83xx) #if !defined(CONFIG_MPC83xx)
static void writeStartSeq(void) static void i2c_write_start_seq(void)
{ {
set_sda(1); set_sda(1);
udelay(DELAY_HALF_PERIOD); udelay(DELAY_HALF_PERIOD);
...@@ -426,6 +432,21 @@ static void writeStartSeq(void) ...@@ -426,6 +432,21 @@ static void writeStartSeq(void)
*/ */
static int i2c_make_abort(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 scl_state = 0;
int sda_state = 0; int sda_state = 0;
int i = 0; int i = 0;
...@@ -449,57 +470,93 @@ static int i2c_make_abort(void) ...@@ -449,57 +470,93 @@ static int i2c_make_abort(void)
} }
if (ret == 0) if (ret == 0)
for (i = 0; i < 5; i++) 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(); get_sda();
#if defined(CONFIG_HARD_I2C)
/* Set the PortPins back to use for I2C */
setports(0);
#endif
return ret; return ret;
} }
#endif #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) #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; struct fsl_i2c *dev;
dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET); dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET);
uchar dummy; 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)); out_8(&dev->cr, (I2C_CR_MSTA));
udelay(DELAY_ABORT_SEQ);
out_8(&dev->cr, (I2C_CR_MEN | I2C_CR_MSTA)); out_8(&dev->cr, (I2C_CR_MEN | I2C_CR_MSTA));
udelay(DELAY_ABORT_SEQ);
dummy = in_8(&dev->dr); dummy = in_8(&dev->dr);
dummy = in_8(&dev->dr); udelay(DELAY_ABORT_SEQ);
if (dummy != 0xff) { last = in_8(&dev->dr);
dummy = in_8(&dev->dr); nbr_read++;
}
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;
/* /*
* disable I2C controller first, otherwhise it thinks we want to * do read until the last bit is 1, but stop if the full eeprom is
* talk to the slave port... * 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 */ for (i = 0; i < 5; i++)
setports(1); i2c_write_start_seq();
if (ret != 0)
printf("[ERROR] i2c abort failed after %d bytes (0x%02x)\n",
nbr_read, last);
return ret;
}
#endif #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() */ /* Now run the AbortSequence() */
i2c_make_abort(); i2c_make_abort();
#if defined(CONFIG_HARD_I2C)
/* Set the PortPins back to use for I2C */
setports(0);
#endif
#endif
} }
#endif #endif
#endif #endif
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册