Browse Source

更新CPU工程:
更新I2C驱动,优化未等数据完全读取成功就关闭I2C所导致的异常;同时优化驱动逻辑以提高驱的兼容性。

helen 2 months ago
parent
commit
ad4f713b92

+ 2 - 0
amt630hv160-freertos-beta/ArkmicroFiles/libcpu-amt630hv160/include/i2c-dw.h

@@ -93,7 +93,9 @@ extern "C" {
 					 DW_IC_INTR_RD_REQ)
 
 #define DW_IC_STATUS_ACTIVITY		0x1
+#define DW_IC_STATUS_TFNF		BIT(1)
 #define DW_IC_STATUS_TFE		BIT(2)
+#define DW_IC_STATUS_RFF		BIT(4)
 #define DW_IC_STATUS_MASTER_ACTIVITY	BIT(5)
 #define DW_IC_STATUS_SLAVE_ACTIVITY	BIT(6)
 

+ 34 - 11
amt630hv160-freertos-beta/ArkmicroFiles/libcpu-amt630hv160/source/i2c-dw.c

@@ -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);
 }