|
|
@@ -488,6 +488,9 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev)
|
|
|
/* Disable the adapter */
|
|
|
__i2c_dw_disable(dev);
|
|
|
|
|
|
+ /* Clear interrupts */
|
|
|
+ dw_readl(dev, DW_IC_CLR_INTR);
|
|
|
+
|
|
|
/* Write standard speed timing parameters */
|
|
|
dw_writel(dev, dev->ss_hcnt, DW_IC_SS_SCL_HCNT);
|
|
|
dw_writel(dev, dev->ss_lcnt, DW_IC_SS_SCL_LCNT);
|
|
|
@@ -564,8 +567,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
|
|
|
* messages into the tx buffer. Even if the size of i2c_msg data is
|
|
|
* longer than the size of the tx buffer, it handles everything.
|
|
|
*/
|
|
|
-static void
|
|
|
-i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
|
|
+static void i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
|
|
{
|
|
|
struct i2c_msg *msgs = dev->msgs;
|
|
|
u32 intr_mask;
|
|
|
@@ -574,6 +576,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
|
|
u32 buf_len = dev->tx_buf_len;
|
|
|
u8 *buf = dev->tx_buf;
|
|
|
int need_restart = 0;
|
|
|
+ u32 status;
|
|
|
|
|
|
intr_mask = DW_IC_INTR_MASTER_MASK;
|
|
|
|
|
|
@@ -611,8 +614,17 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
|
|
need_restart = 1;
|
|
|
}
|
|
|
|
|
|
- tx_limit = dev->tx_fifo_depth - dw_readl(dev, DW_IC_TXFLR);
|
|
|
- rx_limit = dev->rx_fifo_depth - dw_readl(dev, DW_IC_RXFLR);
|
|
|
+ status = dw_readl(dev, DW_IC_STATUS);
|
|
|
+ tx_limit = dw_readl(dev, DW_IC_TXFLR);
|
|
|
+ if (tx_limit == 0 && !(status & DW_IC_STATUS_TFNF))
|
|
|
+ tx_limit = 0;
|
|
|
+ else
|
|
|
+ tx_limit = dev->tx_fifo_depth - tx_limit;
|
|
|
+ rx_limit = dw_readl(dev, DW_IC_RXFLR);
|
|
|
+ if (rx_limit == 0 && (status & DW_IC_STATUS_RFF))
|
|
|
+ rx_limit = 0;
|
|
|
+ else
|
|
|
+ rx_limit = dev->rx_fifo_depth - rx_limit;
|
|
|
|
|
|
while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
|
|
|
u32 cmd = 0;
|
|
|
@@ -682,8 +694,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
|
|
dw_writel(dev, intr_mask, DW_IC_INTR_MASK);
|
|
|
}
|
|
|
|
|
|
-static u8
|
|
|
-i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len)
|
|
|
+static u8 i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len)
|
|
|
{
|
|
|
struct i2c_msg *msgs = dev->msgs;
|
|
|
u32 flags = msgs[dev->msg_read_idx].flags;
|
|
|
@@ -701,11 +712,11 @@ i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len)
|
|
|
}
|
|
|
|
|
|
|
|
|
-static void
|
|
|
-i2c_dw_read(struct dw_i2c_dev *dev)
|
|
|
+static void i2c_dw_read(struct dw_i2c_dev *dev)
|
|
|
{
|
|
|
struct i2c_msg *msgs = dev->msgs;
|
|
|
int rx_valid;
|
|
|
+ u32 status;
|
|
|
|
|
|
for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) {
|
|
|
u32 len;
|
|
|
@@ -722,7 +733,10 @@ i2c_dw_read(struct dw_i2c_dev *dev)
|
|
|
buf = dev->rx_buf;
|
|
|
}
|
|
|
|
|
|
+ status = dw_readl(dev, DW_IC_STATUS);
|
|
|
rx_valid = dw_readl(dev, DW_IC_RXFLR);
|
|
|
+ if (rx_valid == 0 && (status & DW_IC_STATUS_RFF))
|
|
|
+ rx_valid = dev->rx_fifo_depth;
|
|
|
|
|
|
for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
|
|
|
u32 flags = msgs[dev->msg_read_idx].flags;
|
|
|
@@ -750,8 +764,7 @@ i2c_dw_read(struct dw_i2c_dev *dev)
|
|
|
/*
|
|
|
* Prepare controller for a transaction and call i2c_dw_xfer_msg.
|
|
|
*/
|
|
|
-static int
|
|
|
-i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
|
|
+static int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
|
|
{
|
|
|
struct dw_i2c_dev *dev = adap->dw_dev;
|
|
|
int ret;
|
|
|
@@ -787,6 +800,14 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
|
|
goto done;
|
|
|
}
|
|
|
|
|
|
+ if (!dev->cmd_err && dev->status/* == STATUS_READ_IN_PROGRESS */) {
|
|
|
+ u32 stick = xTaskGetTickCount();
|
|
|
+ while (dev->status) {
|
|
|
+ if (xTaskGetTickCount() - stick > pdMS_TO_TICKS(500))
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* We must disable the adapter before returning and signaling the end
|
|
|
* of the current transfer. Otherwise the hardware might continue
|
|
|
@@ -994,8 +1015,10 @@ static void i2c_dw_isr(void *dev_id)
|
|
|
enabled = dw_readl(dev, DW_IC_ENABLE);
|
|
|
stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
|
|
|
TRACE_DEBUG("enabled=%#x stat=%#x\n", enabled, stat);
|
|
|
- if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
|
|
|
+ if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY)) {
|
|
|
+ dw_readl(dev, DW_IC_CLR_INTR);
|
|
|
return;
|
|
|
+ }
|
|
|
|
|
|
i2c_dw_irq_handler_master(dev);
|
|
|
}
|