|
@@ -235,8 +235,47 @@ static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
|
|
|
|
|
|
dev_dbg(i2c->dev, "STOP\n");
|
|
|
|
|
|
- /* stop the transfer */
|
|
|
- iicstat &= ~S3C2410_IICSTAT_START;
|
|
|
+ /*
|
|
|
+ * The datasheet says that the STOP sequence should be:
|
|
|
+ * 1) I2CSTAT.5 = 0 - Clear BUSY (or 'generate STOP')
|
|
|
+ * 2) I2CCON.4 = 0 - Clear IRQPEND
|
|
|
+ * 3) Wait until the stop condition takes effect.
|
|
|
+ * 4*) I2CSTAT.4 = 0 - Clear TXRXEN
|
|
|
+ *
|
|
|
+ * Where, step "4*" is only for buses with the "HDMIPHY" quirk.
|
|
|
+ *
|
|
|
+ * However, after much experimentation, it appears that:
|
|
|
+ * a) normal buses automatically clear BUSY and transition from
|
|
|
+ * Master->Slave when they complete generating a STOP condition.
|
|
|
+ * Therefore, step (3) can be done in doxfer() by polling I2CCON.4
|
|
|
+ * after starting the STOP generation here.
|
|
|
+ * b) HDMIPHY bus does neither, so there is no way to do step 3.
|
|
|
+ * There is no indication when this bus has finished generating
|
|
|
+ * STOP.
|
|
|
+ *
|
|
|
+ * In fact, we have found that as soon as the IRQPEND bit is cleared in
|
|
|
+ * step 2, the HDMIPHY bus generates the STOP condition, and then
|
|
|
+ * immediately starts transferring another data byte, even though the
|
|
|
+ * bus is supposedly stopped. This is presumably because the bus is
|
|
|
+ * still in "Master" mode, and its BUSY bit is still set.
|
|
|
+ *
|
|
|
+ * To avoid these extra post-STOP transactions on HDMI phy devices, we
|
|
|
+ * just disable Serial Output on the bus (I2CSTAT.4 = 0) directly,
|
|
|
+ * instead of first generating a proper STOP condition. This should
|
|
|
+ * float SDA & SCK terminating the transfer. Subsequent transfers
|
|
|
+ * start with a proper START condition, and proceed normally.
|
|
|
+ *
|
|
|
+ * The HDMIPHY bus is an internal bus that always has exactly two
|
|
|
+ * devices, the host as Master and the HDMIPHY device as the slave.
|
|
|
+ * Skipping the STOP condition has been tested on this bus and works.
|
|
|
+ */
|
|
|
+ if (i2c->quirks & QUIRK_HDMIPHY) {
|
|
|
+ /* Stop driving the I2C pins */
|
|
|
+ iicstat &= ~S3C2410_IICSTAT_TXRXEN;
|
|
|
+ } else {
|
|
|
+ /* stop the transfer */
|
|
|
+ iicstat &= ~S3C2410_IICSTAT_START;
|
|
|
+ }
|
|
|
writel(iicstat, i2c->regs + S3C2410_IICSTAT);
|
|
|
|
|
|
i2c->state = STATE_STOP;
|
|
@@ -561,6 +600,10 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
|
|
|
else if (ret != num)
|
|
|
dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
|
|
|
|
|
|
+ /* For QUIRK_HDMIPHY, bus is already disabled */
|
|
|
+ if (i2c->quirks & QUIRK_HDMIPHY)
|
|
|
+ goto out;
|
|
|
+
|
|
|
/* ensure the stop has been through the bus */
|
|
|
|
|
|
dev_dbg(i2c->dev, "waiting for bus idle\n");
|