From 3022105ecdeec0c6b10199bd1e1bc7e0ba9f0cee Mon Sep 17 00:00:00 2001 From: Wayne Zou Date: Tue, 6 Sep 2011 13:43:00 +0800 Subject: ENGR00156098 mx53_smd/mx53_loco: DA9053 I2C SDA stuck low issue on bootup For DA9053 I2C SDA stuck low issue: the I2C block in DA9053 may not correctly receive a Power On Reset and device is in unknown state during start-up. The only way to get the chip into known state before any communication with the Chip via I2C is to dummy clock the I2C and bring it in a state where I2C can communicate. Dialog suggested to provide 9 clock on SCL. Dialog don't know the exact reason for the fault and assume it is because some random noise or spurious behaviour. This has to been done in host platform specific I2C driver during start-up when the I2C is being configured at platform level to supply with dummy 9 clock on SCL. Dialog I2C driver has no control to provide dummy 9 clock on SCL. Signed-off-by: Wayne Zou --- board/freescale/mx53_loco/mx53_loco.c | 103 +++++++++++++++++++++++++++++++++- board/freescale/mx53_smd/mx53_smd.c | 103 +++++++++++++++++++++++++++++++++- 2 files changed, 204 insertions(+), 2 deletions(-) diff --git a/board/freescale/mx53_loco/mx53_loco.c b/board/freescale/mx53_loco/mx53_loco.c index a96c417..963c11e 100644 --- a/board/freescale/mx53_loco/mx53_loco.c +++ b/board/freescale/mx53_loco/mx53_loco.c @@ -322,6 +322,107 @@ static void setup_i2c(unsigned int module_base) void setup_pmic_voltages(void) { } + +/* DA9053 I2C SDA stuck low issue: the I2C block in DA9053 may not correctly + * receive a Power On Reset and device is in unknown state during start-up. + * The only way to get the chip into known state before any communication + * with the Chip via I2C is to dummy clock the I2C and bring it in a state + * where I2C can communicate. Dialog suggested to provide 9 clock on SCL. + * Dialog don't know the exact reason for the fault and assume it is because + * some random noise or spurious behaviour. + * This has to been done in host platform specific I2C driver during + * start-up when the I2C is being configured at platform level to supply with + * dummy 9 clock on SCL. Dialog I2C driver has no control to provide dummy 9 + * clock on SCL. + */ +#define I2C1_SDA_GPIO5_26_BIT_MASK (1 << 26) +#define I2C1_SCL_GPIO5_27_BIT_MASK (1 << 27) +void i2c_failed_handle(void) +{ + unsigned int reg, i, retry = 10; + + do { + /* set I2C1_SDA as GPIO input */ + mxc_request_iomux(MX53_PIN_CSI0_D8, IOMUX_CONFIG_ALT1); + reg = readl(GPIO5_BASE_ADDR + 0x4); + reg &= ~I2C1_SDA_GPIO5_26_BIT_MASK; + writel(reg, GPIO5_BASE_ADDR + 0x4); + + /* set I2C1_SCL as GPIO output */ + mxc_request_iomux(MX53_PIN_CSI0_D9, IOMUX_CONFIG_ALT1); + reg = readl(GPIO5_BASE_ADDR + 0x0); + reg |= I2C1_SCL_GPIO5_27_BIT_MASK; + writel(reg, GPIO5_BASE_ADDR + 0x0); + + reg = readl(GPIO5_BASE_ADDR + 0x4); + reg |= I2C1_SCL_GPIO5_27_BIT_MASK; + writel(reg, GPIO5_BASE_ADDR + 0x4); + udelay(10000); + + for (i = 0; i < 10; i++) { + reg = readl(GPIO5_BASE_ADDR + 0x0); + reg |= I2C1_SCL_GPIO5_27_BIT_MASK; + writel(reg, GPIO5_BASE_ADDR + 0x0); + udelay(5000); + + reg = readl(GPIO5_BASE_ADDR + 0x0); + reg &= ~I2C1_SCL_GPIO5_27_BIT_MASK; + writel(reg, GPIO5_BASE_ADDR + 0x0); + udelay(5000); + } + reg = readl(GPIO5_BASE_ADDR + 0x0); + reg |= I2C1_SCL_GPIO5_27_BIT_MASK; + writel(reg, GPIO5_BASE_ADDR + 0x0); + udelay(1000); + + reg = readl(GPIO5_BASE_ADDR + 0x8); + if (reg & I2C1_SDA_GPIO5_26_BIT_MASK) { + printf("***I2C1_SDA = hight***\n"); + return; + } else { + printf("***I2C1_SDA = low***\n"); + } + } while (retry--); +} + +int i2c_read_check(uchar chip, uint addr, int alen, uchar *buf, int len) +{ + int ret = 0; + + ret = i2c_read(chip, addr, alen, buf, len); + if (ret == 0) { + return 0; + } else { + i2c_failed_handle(); + setup_i2c(CONFIG_SYS_I2C_PORT); + ret = i2c_read(chip, addr, alen, buf, len); + if (ret != 0) { + printf("[I2C-DA9053]read i2c fail\n"); + return -1; + } + return 0; + } +} + +int i2c_write_check(uchar chip, uint addr, int alen, uchar *buf, int len) +{ + int ret = 0; + + ret = i2c_write(chip, addr, alen, buf, len); + if (ret == 0) { + return 0; + } else { + i2c_failed_handle(); + setup_i2c(CONFIG_SYS_I2C_PORT); + i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + ret = i2c_write(chip, addr, alen, buf, len); + if (ret != 0) { + printf("[I2C-DA9053]write i2c fail\n"); + return -1; + } + return 0; + } +} #endif #if defined(CONFIG_DWC_AHSATA) @@ -752,7 +853,7 @@ int board_late_init(void) /* increase VDDGP as 1.25V for 1GHZ */ value = 0x5e; do { - if (0 != i2c_write(0x48, 0x2e, 1, &value, 1)) { + if (0 != i2c_write_check(0x48, 0x2e, 1, &value, 1)) { printf("da9052_i2c_is_connected - i2c write failed.....\n"); } else { printf("da9052_i2c_is_connected - i2c write success....\n"); diff --git a/board/freescale/mx53_smd/mx53_smd.c b/board/freescale/mx53_smd/mx53_smd.c index aa8568b..af69a2d 100644 --- a/board/freescale/mx53_smd/mx53_smd.c +++ b/board/freescale/mx53_smd/mx53_smd.c @@ -400,6 +400,107 @@ static void setup_i2c(unsigned int module_base) } } +/* DA9053 I2C SDA stuck low issue: the I2C block in DA9053 may not correctly + * receive a Power On Reset and device is in unknown state during start-up. + * The only way to get the chip into known state before any communication + * with the Chip via I2C is to dummy clock the I2C and bring it in a state + * where I2C can communicate. Dialog suggested to provide 9 clock on SCL. + * Dialog don't know the exact reason for the fault and assume it is because + * some random noise or spurious behaviour. + * This has to been done in host platform specific I2C driver during + * start-up when the I2C is being configured at platform level to supply with + * dummy 9 clock on SCL. Dialog I2C driver has no control to provide dummy 9 + * clock on SCL. + */ +#define I2C1_SDA_GPIO5_26_BIT_MASK (1 << 26) +#define I2C1_SCL_GPIO5_27_BIT_MASK (1 << 27) +void i2c_failed_handle(void) +{ + unsigned int reg, i, retry = 10; + + do { + /* set I2C1_SDA as GPIO input */ + mxc_request_iomux(MX53_PIN_CSI0_D8, IOMUX_CONFIG_ALT1); + reg = readl(GPIO5_BASE_ADDR + 0x4); + reg &= ~I2C1_SDA_GPIO5_26_BIT_MASK; + writel(reg, GPIO5_BASE_ADDR + 0x4); + + /* set I2C1_SCL as GPIO output */ + mxc_request_iomux(MX53_PIN_CSI0_D9, IOMUX_CONFIG_ALT1); + reg = readl(GPIO5_BASE_ADDR + 0x0); + reg |= I2C1_SCL_GPIO5_27_BIT_MASK; + writel(reg, GPIO5_BASE_ADDR + 0x0); + + reg = readl(GPIO5_BASE_ADDR + 0x4); + reg |= I2C1_SCL_GPIO5_27_BIT_MASK; + writel(reg, GPIO5_BASE_ADDR + 0x4); + udelay(10000); + + for (i = 0; i < 10; i++) { + reg = readl(GPIO5_BASE_ADDR + 0x0); + reg |= I2C1_SCL_GPIO5_27_BIT_MASK; + writel(reg, GPIO5_BASE_ADDR + 0x0); + udelay(5000); + + reg = readl(GPIO5_BASE_ADDR + 0x0); + reg &= ~I2C1_SCL_GPIO5_27_BIT_MASK; + writel(reg, GPIO5_BASE_ADDR + 0x0); + udelay(5000); + } + reg = readl(GPIO5_BASE_ADDR + 0x0); + reg |= I2C1_SCL_GPIO5_27_BIT_MASK; + writel(reg, GPIO5_BASE_ADDR + 0x0); + udelay(1000); + + reg = readl(GPIO5_BASE_ADDR + 0x8); + if (reg & I2C1_SDA_GPIO5_26_BIT_MASK) { + printf("***I2C1_SDA = hight***\n"); + return; + } else { + printf("***I2C1_SDA = low***\n"); + } + } while (retry--); +} + +int i2c_read_check(uchar chip, uint addr, int alen, uchar *buf, int len) +{ + int ret = 0; + + ret = i2c_read(chip, addr, alen, buf, len); + if (ret == 0) { + return 0; + } else { + i2c_failed_handle(); + setup_i2c(CONFIG_SYS_I2C_PORT); + ret = i2c_read(chip, addr, alen, buf, len); + if (ret != 0) { + printf("[I2C-DA9053]read i2c fail\n"); + return -1; + } + return 0; + } +} + +int i2c_write_check(uchar chip, uint addr, int alen, uchar *buf, int len) +{ + int ret = 0; + + ret = i2c_write(chip, addr, alen, buf, len); + if (ret == 0) { + return 0; + } else { + i2c_failed_handle(); + setup_i2c(CONFIG_SYS_I2C_PORT); + i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + ret = i2c_write(chip, addr, alen, buf, len); + if (ret != 0) { + printf("[I2C-DA9053]write i2c fail\n"); + return -1; + } + return 0; + } +} + /* restore VUSB 2V5 active after suspend */ #define BUCKPERI_RESTORE_SW_STEP (0x55) /* restore VUSB 2V5 power supply after suspend */ @@ -415,7 +516,7 @@ void setup_pmic_voltages(void) /* increase VDDGP as 1.25V for 1GHZ */ value = 0x5e; do { - if (0 != i2c_write(0x48, 0x2e, 1, &value, 1)) { + if (0 != i2c_write_check(0x48, 0x2e, 1, &value, 1)) { printf("da9052_i2c_is_connected - i2c write failed.....\n"); } else { printf("da9052_i2c_is_connected - i2c write success....\n"); -- cgit v1.1