AnsweredAssumed Answered

mx287 i2c slave with linux-3.7.6

Question asked by Alric Fitterer on Apr 16, 2013
Latest reply on Aug 19, 2013 by Yixing Kong
Branched to a new discussion

Hi all,


I'm working with an mx287, linux-3.7.6 (buildroot) and need one of the i2c's to be a slave (100KHz). I have reviewed the mx28_i2c_slave_demo.patch that has been referenced in several discussions on this site. The patch appears to be for an older kernel (not sure which one), and linux-3.7.6 seems to have changed to the extent that it did not help enough on this issue.

I have managed to get the DMA to read in the data from a master i2c. However the data and clock lines are held low after the last byte received by the i2c slave. I have tried to clear the CLOCK_HELD in the I2C_CTRL0 register and/or set the FORCE_DATA_IDLE and FORCE_CLK_IDLE in the CRTL1 register (these were done in almost every combination) from the DATA_ENGINE_CMPLT_IRQ interrupt, with no success. Can anyone provide some direction as how to get the data and clock to be released?

Per MCIMX28RM section Slave Mode Protocol,

The DMA engine stops with the clock held and the hardware ready to acknowledge the last byte when the clock is released. Software decides whether the last byte is acknowledged or not.

How can this be done with DMA?


Per the Slave Mode Protocol, I need to release the clock after the last byte, did this in DATA_ENGINE_CMPLT_IRQ interrupt with CLOCK_HELD in the I2C_CTRL0 register and it didn't work. Any help would be appreciated.


And for some code,


initialization code:


writel(i2c->slave_address, i2c->regs + MXS_I2C_CTRL1_SET);

writel((MXS_I2C_CTRL1_ACK_MODE), i2c->regs + MXS_I2C_CTRL1_SET);



  i2c->regs + MXS_I2C_CTRL0_CLR);



  i2c->regs + MXS_I2C_CTRL0_SET);


DMA descriptor after CTRL1_SLAVE_IRQ interrupt and detection that a write is seen from the i2c master:


i2c->pio_data[0] = flags | MXS_CMD_I2C_READ |


desc = dmaengine_prep_slave_sg(i2c->dmach,

                    (struct scatterlist *)&i2c->pio_data[0],

                    1, DMA_TRANS_NONE, 0);

sg_init_one(&i2c->sg_io[0], msg->buf, msg->len);

desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[0], 1,


                    DMA_PREP_INTERRUPT | DMA_CTRL_ACK);


     * The last descriptor must have this callback,

     * to finish the DMA transaction.


    desc->callback = mxs_i2c_dma_irq_callback;

    desc->callback_param = i2c;


    /* Start the transfer. */