From: Anders Berg <anders.b...@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.b...@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.4.3 _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto