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
This commit is contained in:
Amaury Pouly 2013-09-06 18:19:09 +02:00
parent f40b15d0cb
commit 164876eaf1

View file

@ -80,12 +80,18 @@ void INT_I2C_DMA(void)
semaphore_release(&i2c_sema); 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 */ /* clear softreset */
imx233_reset_block(&HW_I2C_CTRL0); imx233_reset_block(&HW_I2C_CTRL0);
/* Errata (imx233): /* Errata (imx233):
@ -103,7 +109,15 @@ void imx233_i2c_init(void)
HW_I2C_TIMING0 = 0x000F0007; /* tHIGH=0.6us, read at 0.3us */ HW_I2C_TIMING0 = 0x000F0007; /* tHIGH=0.6us, read at 0.3us */
HW_I2C_TIMING1 = 0x001F000F; /* tLOW=1.3us, write at 0.6us */ HW_I2C_TIMING1 = 0x001F000F; /* tLOW=1.3us, write at 0.6us */
HW_I2C_TIMING2 = 0x0015000D; 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); mutex_init(&i2c_mutex);
semaphore_init(&i2c_sema, 1, 0); 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); BF_CLR(I2C_CTRL1, ALL_IRQ);
imx233_dma_reset_channel(APB_I2C); imx233_dma_reset_channel(APB_I2C);
imx233_icoll_enable_interrupt(INT_SRC_I2C_DMA, true); 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_enable_channel_interrupt(APB_I2C, true);
imx233_dma_start_command(APB_I2C, &i2c_stage[0].dma); 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)) else if(BF_RD(I2C_CTRL1, MASTER_LOSS_IRQ))
ret = I2C_MASTER_LOSS; ret = I2C_MASTER_LOSS;
else if(BF_RD(I2C_CTRL1, NO_SLAVE_ACK_IRQ)) 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; ret= I2C_NO_SLAVE_ACK;
}
else if(BF_RD(I2C_CTRL1, EARLY_TERM_IRQ)) else if(BF_RD(I2C_CTRL1, EARLY_TERM_IRQ))
ret = I2C_SLAVE_NAK; ret = I2C_SLAVE_NAK;
else else