aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/mediatek/patches-5.15/843-v5.18-i2c-mediatek-modify-bus-speed-calculation-formula.patch
blob: 0ace4a6701c5d5d73e44f2b5743bc195643aba83 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
From f606aab3f1a49d723d66e14e545f6ca45005bda6 Mon Sep 17 00:00:00 2001
From: Kewei Xu <kewei.xu@mediatek.com>
Date: Thu, 17 Feb 2022 20:22:43 +0800
Subject: [PATCH 04/16] i2c: mediatek: modify bus speed calculation formula

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: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: Qii Wang <qii.wang@mediatek.com>
Signed-off-by: Wolfram Sang <wsa@kernel.org>
---
 drivers/i2c/busses/i2c-mt65xx.c | 51 ++++++++++++++++++++++++++-------
 1 file changed, 41 insertions(+), 10 deletions(-)

--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -67,11 +67,12 @@
 
 #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)
 
 #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
 		return MAX_STEP_CNT_DIV;
 }
 
+static int mtk_i2c_get_clk_div_restri(struct mtk_i2c *i2c,
+				      unsigned int sample_cnt)
+{
+	int clk_div_restri = 0;
+
+	if (i2c->dev_comp->ltiming_adjust == 0)
+		return 0;
+
+	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;
+	}
+
+	return clk_div_restri;
+}
+
 /*
  * Check and Calculate i2c ac-timing
  *
@@ -732,6 +758,7 @@ static int mtk_i2c_calculate_speed(struc
 	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(struc
 	 * 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(struc
 			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(struc
 	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_
 	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_
 		break;
 	}
 
-	i2c->ac_timing.inter_clk_div = clk_div - 1;
 
 	return 0;
 }