0ace4a6701c5d5d73e44f2b5743bc195643aba83
[openwrt/staging/blogic.git] /
1 From f606aab3f1a49d723d66e14e545f6ca45005bda6 Mon Sep 17 00:00:00 2001
2 From: Kewei Xu <kewei.xu@mediatek.com>
3 Date: Thu, 17 Feb 2022 20:22:43 +0800
4 Subject: [PATCH 04/16] i2c: mediatek: modify bus speed calculation formula
5
6 When clock-div is 0 or greater than 1, the bus speed
7 calculated by the old speed calculation formula will be
8 larger than the target speed. So we update the formula.
9
10 Signed-off-by: Kewei Xu <kewei.xu@mediatek.com>
11 Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
12 Reviewed-by: Qii Wang <qii.wang@mediatek.com>
13 Signed-off-by: Wolfram Sang <wsa@kernel.org>
14 ---
15 drivers/i2c/busses/i2c-mt65xx.c | 51 ++++++++++++++++++++++++++-------
16 1 file changed, 41 insertions(+), 10 deletions(-)
17
18 --- a/drivers/i2c/busses/i2c-mt65xx.c
19 +++ b/drivers/i2c/busses/i2c-mt65xx.c
20 @@ -67,11 +67,12 @@
21
22 #define MAX_SAMPLE_CNT_DIV 8
23 #define MAX_STEP_CNT_DIV 64
24 -#define MAX_CLOCK_DIV 256
25 +#define MAX_CLOCK_DIV_8BITS 256
26 +#define MAX_CLOCK_DIV_5BITS 32
27 #define MAX_HS_STEP_CNT_DIV 8
28 -#define I2C_STANDARD_MODE_BUFFER (1000 / 2)
29 -#define I2C_FAST_MODE_BUFFER (300 / 2)
30 -#define I2C_FAST_MODE_PLUS_BUFFER (20 / 2)
31 +#define I2C_STANDARD_MODE_BUFFER (1000 / 3)
32 +#define I2C_FAST_MODE_BUFFER (300 / 3)
33 +#define I2C_FAST_MODE_PLUS_BUFFER (20 / 3)
34
35 #define I2C_CONTROL_RS (0x1 << 1)
36 #define I2C_CONTROL_DMA_EN (0x1 << 2)
37 @@ -604,6 +605,31 @@ static int mtk_i2c_max_step_cnt(unsigned
38 return MAX_STEP_CNT_DIV;
39 }
40
41 +static int mtk_i2c_get_clk_div_restri(struct mtk_i2c *i2c,
42 + unsigned int sample_cnt)
43 +{
44 + int clk_div_restri = 0;
45 +
46 + if (i2c->dev_comp->ltiming_adjust == 0)
47 + return 0;
48 +
49 + if (sample_cnt == 1) {
50 + if (i2c->ac_timing.inter_clk_div == 0)
51 + clk_div_restri = 0;
52 + else
53 + clk_div_restri = 1;
54 + } else {
55 + if (i2c->ac_timing.inter_clk_div == 0)
56 + clk_div_restri = -1;
57 + else if (i2c->ac_timing.inter_clk_div == 1)
58 + clk_div_restri = 0;
59 + else
60 + clk_div_restri = 1;
61 + }
62 +
63 + return clk_div_restri;
64 +}
65 +
66 /*
67 * Check and Calculate i2c ac-timing
68 *
69 @@ -732,6 +758,7 @@ static int mtk_i2c_calculate_speed(struc
70 unsigned int best_mul;
71 unsigned int cnt_mul;
72 int ret = -EINVAL;
73 + int clk_div_restri = 0;
74
75 if (target_speed > I2C_MAX_HIGH_SPEED_MODE_FREQ)
76 target_speed = I2C_MAX_HIGH_SPEED_MODE_FREQ;
77 @@ -749,7 +776,8 @@ static int mtk_i2c_calculate_speed(struc
78 * optimizing for sample_cnt * step_cnt being minimal
79 */
80 for (sample_cnt = 1; sample_cnt <= MAX_SAMPLE_CNT_DIV; sample_cnt++) {
81 - step_cnt = DIV_ROUND_UP(opt_div, sample_cnt);
82 + clk_div_restri = mtk_i2c_get_clk_div_restri(i2c, sample_cnt);
83 + step_cnt = DIV_ROUND_UP(opt_div + clk_div_restri, sample_cnt);
84 cnt_mul = step_cnt * sample_cnt;
85 if (step_cnt > max_step_cnt)
86 continue;
87 @@ -763,7 +791,7 @@ static int mtk_i2c_calculate_speed(struc
88 best_mul = cnt_mul;
89 base_sample_cnt = sample_cnt;
90 base_step_cnt = step_cnt;
91 - if (best_mul == opt_div)
92 + if (best_mul == (opt_div + clk_div_restri))
93 break;
94 }
95 }
96 @@ -774,7 +802,8 @@ static int mtk_i2c_calculate_speed(struc
97 sample_cnt = base_sample_cnt;
98 step_cnt = base_step_cnt;
99
100 - if ((clk_src / (2 * sample_cnt * step_cnt)) > target_speed) {
101 + if ((clk_src / (2 * (sample_cnt * step_cnt - clk_div_restri))) >
102 + target_speed) {
103 /* In this case, hardware can't support such
104 * low i2c_bus_freq
105 */
106 @@ -803,13 +832,16 @@ static int mtk_i2c_set_speed(struct mtk_
107 target_speed = i2c->speed_hz;
108 parent_clk /= i2c->clk_src_div;
109
110 - if (i2c->dev_comp->timing_adjust)
111 - max_clk_div = MAX_CLOCK_DIV;
112 + if (i2c->dev_comp->timing_adjust && i2c->dev_comp->ltiming_adjust)
113 + max_clk_div = MAX_CLOCK_DIV_5BITS;
114 + else if (i2c->dev_comp->timing_adjust)
115 + max_clk_div = MAX_CLOCK_DIV_8BITS;
116 else
117 max_clk_div = 1;
118
119 for (clk_div = 1; clk_div <= max_clk_div; clk_div++) {
120 clk_src = parent_clk / clk_div;
121 + i2c->ac_timing.inter_clk_div = clk_div - 1;
122
123 if (target_speed > I2C_MAX_FAST_MODE_PLUS_FREQ) {
124 /* Set master code speed register */
125 @@ -856,7 +888,6 @@ static int mtk_i2c_set_speed(struct mtk_
126 break;
127 }
128
129 - i2c->ac_timing.inter_clk_div = clk_div - 1;
130
131 return 0;
132 }