--- v8
+++ v9
@@ -1,72 +1,130 @@
-Due to changes in the hardware design of the handshaking signal
-between i2c and dma, it is necessary to reset the handshaking
-signal before each transfer to ensure that the multi-msgs can
-be transferred correctly.
+When clock-div is 0 or greater than 1, the bus speed
+calculated by the old speed calculation formula will be
+larger than the target speed. So we update the formula.
Signed-off-by: Kewei Xu <kewei.xu@mediatek.com>
-Reviewed-by: Qii Wang <qii.wang@mediatek.com>
+Change-Id: Ic0d9b8ab036bcf215d3a5066f2b91c7b8b128ba6
---
- drivers/i2c/busses/i2c-mt65xx.c | 26 ++++++++++++++++++++++++++
- 1 file changed, 26 insertions(+)
+ drivers/i2c/busses/i2c-mt65xx.c | 51 +++++++++++++++++++++++++++++++++--------
+ 1 file changed, 41 insertions(+), 10 deletions(-)
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
-index 72acda59eb39..dad3a85cd499 100644
+index aa4d218..682293e 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
-@@ -15,6 +15,7 @@
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/io.h>
-+#include <linux/iopoll.h>
- #include <linux/kernel.h>
- #include <linux/mm.h>
- #include <linux/module.h>
-@@ -49,6 +50,8 @@
- #define I2C_RD_TRANAC_VALUE 0x0001
- #define I2C_SCL_MIS_COMP_VALUE 0x0000
- #define I2C_CHN_CLR_FLAG 0x0000
-+#define I2C_RELIABILITY 0x0010
-+#define I2C_DMAACK_ENABLE 0x0008
+@@ -67,11 +67,12 @@
- #define I2C_DMA_CON_TX 0x0000
- #define I2C_DMA_CON_RX 0x0001
-@@ -851,6 +854,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
- u16 restart_flag = 0;
- u16 dma_sync = 0;
- u32 reg_4g_mode;
-+ u32 reg_dma_reset;
- u8 *dma_rd_buf = NULL;
- u8 *dma_wr_buf = NULL;
- dma_addr_t rpaddr = 0;
-@@ -864,6 +868,28 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
+ #define MAX_SAMPLE_CNT_DIV 8
+ #define MAX_STEP_CNT_DIV 64
+-#define MAX_CLOCK_DIV 256
++#define MAX_CLOCK_DIV_8BITS 256
++#define MAX_CLOCK_DIV_5BITS 32
+ #define MAX_HS_STEP_CNT_DIV 8
+-#define I2C_STANDARD_MODE_BUFFER (1000 / 2)
+-#define I2C_FAST_MODE_BUFFER (300 / 2)
+-#define I2C_FAST_MODE_PLUS_BUFFER (20 / 2)
++#define I2C_STANDARD_MODE_BUFFER (1000 / 3)
++#define I2C_FAST_MODE_BUFFER (300 / 3)
++#define I2C_FAST_MODE_PLUS_BUFFER (20 / 3)
- reinit_completion(&i2c->msg_complete);
+ #define I2C_CONTROL_RS (0x1 << 1)
+ #define I2C_CONTROL_DMA_EN (0x1 << 2)
+@@ -604,6 +605,31 @@ static int mtk_i2c_max_step_cnt(unsigned int target_speed)
+ return MAX_STEP_CNT_DIV;
+ }
-+ if (i2c->dev_comp->apdma_sync &&
-+ i2c->op != I2C_MASTER_WRRD && num > 1) {
-+ mtk_i2c_writew(i2c, 0x00, OFFSET_DEBUGCTRL);
-+ writel(I2C_DMA_HANDSHAKE_RST | I2C_DMA_WARM_RST,
-+ i2c->pdmabase + OFFSET_RST);
++static int mtk_i2c_get_clk_div_restri(struct mtk_i2c *i2c,
++ unsigned int sample_cnt)
++{
++ int clk_div_restri = 0;
+
-+ ret = readw_poll_timeout(i2c->pdmabase + OFFSET_RST,
-+ reg_dma_reset,
-+ !(reg_dma_reset & I2C_DMA_WARM_RST),
-+ 0, 100);
-+ if (ret) {
-+ dev_err(i2c->dev, "DMA warm reset timeout\n");
-+ return -ETIMEDOUT;
-+ }
++ if (i2c->dev_comp->ltiming_adjust == 0)
++ return 0;
+
-+ writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_RST);
-+ mtk_i2c_writew(i2c, I2C_HANDSHAKE_RST, OFFSET_SOFTRESET);
-+ mtk_i2c_writew(i2c, I2C_CHN_CLR_FLAG, OFFSET_SOFTRESET);
-+ mtk_i2c_writew(i2c, I2C_RELIABILITY | I2C_DMAACK_ENABLE,
-+ OFFSET_DEBUGCTRL);
++ if (sample_cnt == 1) {
++ if (i2c->ac_timing.inter_clk_div == 0)
++ clk_div_restri = 0;
++ else
++ clk_div_restri = 1;
++ } else {
++ if (i2c->ac_timing.inter_clk_div == 0)
++ clk_div_restri = -1;
++ else if (i2c->ac_timing.inter_clk_div == 1)
++ clk_div_restri = 0;
++ else
++ clk_div_restri = 1;
+ }
+
- control_reg = mtk_i2c_readw(i2c, OFFSET_CONTROL) &
- ~(I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS);
- if ((i2c->speed_hz > I2C_MAX_FAST_MODE_PLUS_FREQ) || (left_num >= 1))
++ return clk_div_restri;
++}
++
+ /*
+ * Check and Calculate i2c ac-timing
+ *
+@@ -732,6 +758,7 @@ static int mtk_i2c_calculate_speed(struct mtk_i2c *i2c, unsigned int clk_src,
+ unsigned int best_mul;
+ unsigned int cnt_mul;
+ int ret = -EINVAL;
++ int clk_div_restri = 0;
+
+ if (target_speed > I2C_MAX_HIGH_SPEED_MODE_FREQ)
+ target_speed = I2C_MAX_HIGH_SPEED_MODE_FREQ;
+@@ -749,7 +776,8 @@ static int mtk_i2c_calculate_speed(struct mtk_i2c *i2c, unsigned int clk_src,
+ * optimizing for sample_cnt * step_cnt being minimal
+ */
+ for (sample_cnt = 1; sample_cnt <= MAX_SAMPLE_CNT_DIV; sample_cnt++) {
+- step_cnt = DIV_ROUND_UP(opt_div, sample_cnt);
++ clk_div_restri = mtk_i2c_get_clk_div_restri(i2c, sample_cnt);
++ step_cnt = DIV_ROUND_UP(opt_div + clk_div_restri, sample_cnt);
+ cnt_mul = step_cnt * sample_cnt;
+ if (step_cnt > max_step_cnt)
+ continue;
+@@ -763,7 +791,7 @@ static int mtk_i2c_calculate_speed(struct mtk_i2c *i2c, unsigned int clk_src,
+ best_mul = cnt_mul;
+ base_sample_cnt = sample_cnt;
+ base_step_cnt = step_cnt;
+- if (best_mul == opt_div)
++ if (best_mul == (opt_div + clk_div_restri))
+ break;
+ }
+ }
+@@ -774,7 +802,8 @@ static int mtk_i2c_calculate_speed(struct mtk_i2c *i2c, unsigned int clk_src,
+ sample_cnt = base_sample_cnt;
+ step_cnt = base_step_cnt;
+
+- if ((clk_src / (2 * sample_cnt * step_cnt)) > target_speed) {
++ if ((clk_src / (2 * (sample_cnt * step_cnt - clk_div_restri))) >
++ target_speed) {
+ /* In this case, hardware can't support such
+ * low i2c_bus_freq
+ */
+@@ -803,13 +832,16 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk)
+ target_speed = i2c->speed_hz;
+ parent_clk /= i2c->clk_src_div;
+
+- if (i2c->dev_comp->timing_adjust)
+- max_clk_div = MAX_CLOCK_DIV;
++ if (i2c->dev_comp->timing_adjust && i2c->dev_comp->ltiming_adjust)
++ max_clk_div = MAX_CLOCK_DIV_5BITS;
++ else if (i2c->dev_comp->timing_adjust)
++ max_clk_div = MAX_CLOCK_DIV_8BITS;
+ else
+ max_clk_div = 1;
+
+ for (clk_div = 1; clk_div <= max_clk_div; clk_div++) {
+ clk_src = parent_clk / clk_div;
++ i2c->ac_timing.inter_clk_div = clk_div - 1;
+
+ if (target_speed > I2C_MAX_FAST_MODE_PLUS_FREQ) {
+ /* Set master code speed register */
+@@ -856,7 +888,6 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk)
+ break;
+ }
+
+- i2c->ac_timing.inter_clk_div = clk_div - 1;
+
+ return 0;
+ }
--
-2.25.1
+1.9.1