summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx233/i2c-imx233.c
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2013-09-06 18:19:09 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2013-09-06 18:19:09 +0200
commit164876eaf1b586505566c6f32bb873a958a12331 (patch)
tree3b1a33ae24b18f7af5b3a375940ef30f9d4704da /firmware/target/arm/imx233/i2c-imx233.c
parentf40b15d0cbe726e72652fcd8ff775d08b19affda (diff)
imx233: fix i2c issues
The i2c core has some bugs: it locks up when the slave doesn't NAK and prevent the dma channel from being resetted. Specifically handle this situation by setting CLR_GOT_A_NAK (workaround) and then reset dma and i2c block. Change-Id: I0e09d38d4301a0ad42dfad785cc934b43f2c4485
Diffstat (limited to 'firmware/target/arm/imx233/i2c-imx233.c')
-rw-r--r--firmware/target/arm/imx233/i2c-imx233.c33
1 files changed, 27 insertions, 6 deletions
diff --git a/firmware/target/arm/imx233/i2c-imx233.c b/firmware/target/arm/imx233/i2c-imx233.c
index ee5ac1ccf6..f99cd97282 100644
--- a/firmware/target/arm/imx233/i2c-imx233.c
+++ b/firmware/target/arm/imx233/i2c-imx233.c
@@ -80,12 +80,18 @@ void INT_I2C_DMA(void)
semaphore_release(&i2c_sema);
}
-void imx233_i2c_init(void)
+void INT_I2C_ERROR(void)
+{
+ /* reset dma channel on error */
+ if(imx233_dma_is_channel_error_irq(APB_I2C))
+ imx233_dma_reset_channel(APB_I2C);
+ /* clear irq flags */
+ imx233_dma_clear_channel_interrupt(APB_I2C);
+ semaphore_release(&i2c_sema);
+}
+
+static void imx233_i2c_reset(void)
{
- BF_SET(I2C_CTRL0, SFTRST);
- /* setup pins (must be done when shutdown) */
- imx233_pinctrl_setup_vpin(VPIN_I2C_SCL, "i2c scl", PINCTRL_DRIVE_4mA, true);
- imx233_pinctrl_setup_vpin(VPIN_I2C_SDA, "i2c sda", PINCTRL_DRIVE_4mA, true);
/* clear softreset */
imx233_reset_block(&HW_I2C_CTRL0);
/* Errata (imx233):
@@ -103,7 +109,15 @@ void imx233_i2c_init(void)
HW_I2C_TIMING0 = 0x000F0007; /* tHIGH=0.6us, read at 0.3us */
HW_I2C_TIMING1 = 0x001F000F; /* tLOW=1.3us, write at 0.6us */
HW_I2C_TIMING2 = 0x0015000D;
-
+}
+
+void imx233_i2c_init(void)
+{
+ BF_SET(I2C_CTRL0, SFTRST);
+ /* setup pins (must be done when shutdown) */
+ imx233_pinctrl_setup_vpin(VPIN_I2C_SCL, "i2c scl", PINCTRL_DRIVE_4mA, true);
+ imx233_pinctrl_setup_vpin(VPIN_I2C_SDA, "i2c sda", PINCTRL_DRIVE_4mA, true);
+ imx233_i2c_reset();
mutex_init(&i2c_mutex);
semaphore_init(&i2c_sema, 1, 0);
}
@@ -183,6 +197,7 @@ enum imx233_i2c_error_t imx233_i2c_end(unsigned timeout)
BF_CLR(I2C_CTRL1, ALL_IRQ);
imx233_dma_reset_channel(APB_I2C);
imx233_icoll_enable_interrupt(INT_SRC_I2C_DMA, true);
+ imx233_icoll_enable_interrupt(INT_SRC_I2C_ERROR, true);
imx233_dma_enable_channel_interrupt(APB_I2C, true);
imx233_dma_start_command(APB_I2C, &i2c_stage[0].dma);
@@ -195,7 +210,13 @@ enum imx233_i2c_error_t imx233_i2c_end(unsigned timeout)
else if(BF_RD(I2C_CTRL1, MASTER_LOSS_IRQ))
ret = I2C_MASTER_LOSS;
else if(BF_RD(I2C_CTRL1, NO_SLAVE_ACK_IRQ))
+ {
+ /* the core doesn't like this error, this is a workaround to prevent lock up */
+ BF_SET(I2C_CTRL1, CLR_GOT_A_NAK);
+ imx233_dma_reset_channel(APB_I2C);
+ imx233_i2c_reset();
ret= I2C_NO_SLAVE_ACK;
+ }
else if(BF_RD(I2C_CTRL1, EARLY_TERM_IRQ))
ret = I2C_SLAVE_NAK;
else