[linux-yocto] [PATCH 57/89] drivers/i2c: Corrected WAIT_TIMER timeout calculation.
Paul Butler
butler.paul at gmail.com
Sun Oct 27 12:33:22 PDT 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