[linux-yocto] [PATCH 65/94] drivers/i2c: Corrected WAIT_TIMER timeout calculation.

Paul Butler butler.paul at gmail.com
Thu Nov 7 17:13:19 PST 2013


From: Anders Berg <anders.berg at lsi.com>

Select prescaler divider so that the timeout value doesn't overflow the 15 bits
reseved for it.

Signed-off-by: Anders Berg <anders.berg at lsi.com>
---
 drivers/i2c/busses/ai2c/ai2c_mod.c |  6 +++---
 drivers/i2c/busses/i2c-axxia.c     | 41 ++++++++++++++++++++++++++++----------
 2 files changed, 34 insertions(+), 13 deletions(-)

diff --git a/drivers/i2c/busses/ai2c/ai2c_mod.c b/drivers/i2c/busses/ai2c/ai2c_mod.c
index 6692b2e..019a2d8 100644
--- a/drivers/i2c/busses/ai2c/ai2c_mod.c
+++ b/drivers/i2c/busses/ai2c/ai2c_mod.c
@@ -1204,7 +1204,7 @@ ai2c_return:
 }
 
 int ai2c_stateSetup(
-    struct ai2c_priv           **outPriv)
+	struct ai2c_priv           **outPriv)
 {
 	int                     ai2cStatus = AI2C_ST_SUCCESS;
 	struct ai2c_priv        *priv = NULL;
@@ -1234,8 +1234,8 @@ ai2c_return:
 }
 
 int ai2c_memSetup(
-    struct platform_device      *pdev,
-    struct ai2c_priv            *priv)
+	struct platform_device      *pdev,
+	struct ai2c_priv            *priv)
 {
 	int                     ai2cStatus = AI2C_ST_SUCCESS;
 	struct axxia_i2c_bus_platform_data  *pdata;
diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c
index 1dd58d9..c71f521 100644
--- a/drivers/i2c/busses/i2c-axxia.c
+++ b/drivers/i2c/busses/i2c-axxia.c
@@ -26,9 +26,10 @@
 #include <linux/of_i2c.h>
 #include <linux/module.h>
 
-#define I2C_TIMEOUT   (msecs_to_jiffies(1000))
-#define TX_FIFO_SIZE  8
-#define RX_FIFO_SIZE  8
+#define SCL_WAIT_TIMEOUT_NS 25000000
+#define I2C_TIMEOUT         (msecs_to_jiffies(1000))
+#define TX_FIFO_SIZE        8
+#define RX_FIFO_SIZE        8
 
 struct i2c_regs {
 	__le32 global_control;
@@ -60,12 +61,16 @@ struct i2c_regs {
 #define MST_STATUS_SNS (1<<11) /* Manual mode done */
 #define MST_STATUS_SS  (1<<10) /* Automatic mode done */
 #define MST_STATUS_SCC (1<<9)  /* Stop complete */
+#define MST_STATUS_IP  (1<<8)  /* Invalid parameter */
 #define MST_STATUS_TSS (1<<7)  /* Timeout */
 #define MST_STATUS_AL  (1<<6)  /* Arbitration lost */
 #define MST_STATUS_NAK (MST_STATUS_NA | MST_STATUS_ND)
 #define MST_STATUS_ND  (1<<5)  /* NAK on data phase */
 #define MST_STATUS_NA  (1<<4)  /* NAK on address phase */
-#define MST_STATUS_ERR (MST_STATUS_NAK | MST_STATUS_AL | MST_STATUS_TSS)
+#define MST_STATUS_ERR (MST_STATUS_NAK | \
+			MST_STATUS_AL  | \
+			MST_STATUS_IP  | \
+			MST_STATUS_TSS)
 	__le32 mst_tx_bytes_xfrd;
 	__le32 mst_rx_bytes_xfrd;
 	__le32 slv_addr_dec_ctl;
@@ -152,7 +157,7 @@ i2c_int_enable(struct axxia_i2c_dev *idev, u32 mask)
 static u32
 ns_to_clk(u64 ns, u32 clk_mhz)
 {
-	return div64_u64(ns*clk_mhz, 1000ULL);
+	return div_u64(ns*clk_mhz, 1000);
 }
 
 static int
@@ -161,6 +166,8 @@ axxia_i2c_init(struct axxia_i2c_dev *idev)
 	u32 divisor = clk_get_rate(idev->i2c_clk) / idev->bus_clk_rate;
 	u32 clk_mhz = clk_get_rate(idev->i2c_clk) / 1000000;
 	u32 t_setup;
+	u32 tmo_clk;
+	u32 prescale;
 
 	dev_dbg(idev->dev, "rate=%uHz per_clk=%uMHz -> ratio=1:%u\n",
 		idev->bus_clk_rate, clk_mhz, divisor);
@@ -185,12 +192,24 @@ axxia_i2c_init(struct axxia_i2c_dev *idev)
 	writel(ns_to_clk(50, clk_mhz), &idev->regs->spike_fltr_len);
 
 	/* Configure Time-Out Registers */
+	tmo_clk = ns_to_clk(SCL_WAIT_TIMEOUT_NS, clk_mhz);
+
+	/*
+	   Find the prescaler value that makes tmo_clk fit in 15-bits counter.
+	 */
+	for (prescale=0; prescale < 15; ++prescale) {
+		if (tmo_clk <= 0x7fff)
+			break;
+		tmo_clk >>= 1;
+	}
+	if (tmo_clk > 0x7fff) {
+		tmo_clk = 0x7fff;
+	}
 
-	/* Divide by 32 (2^5) */
-	writel(5, &idev->regs->timer_clock_div);
-
-	/* Desired Time-Out = 250ms */
-	writel(ns_to_clk(25000000, clk_mhz), &idev->regs->wait_timer_control);
+	/* Prescale divider (log2) */
+	writel(prescale, &idev->regs->timer_clock_div);
+	/* Timeout in divided clocks */
+	writel((1<<15) | tmo_clk, &idev->regs->wait_timer_control);
 
 	/* Interrupt enable */
 	writel(0x01, &idev->regs->interrupt_enable);
@@ -380,6 +399,8 @@ axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg, int stop)
 		return -ETIMEDOUT;
 	}
 
+	WARN_ON(readl(&idev->regs->mst_command) & 0x8);
+
 	dev_dbg(idev->dev, "transfer complete: %d %d %#x\n",
 		ret, completion_done(&idev->msg_complete), idev->msg_err);
 
-- 
1.8.3.4




More information about the linux-yocto mailing list