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;
}
|