]>
Commit | Line | Data |
---|---|---|
9ad71f63 WG |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright (C) 2022 MediaTek Inc. All Rights Reserved. | |
4 | * | |
5 | * Author: Mingming Lee <[email protected]> | |
6 | * | |
7 | * MediaTek I2C Interface driver | |
8 | */ | |
9 | ||
10 | #include <clk.h> | |
11 | #include <cpu_func.h> | |
12 | #include <dm.h> | |
13 | #include <i2c.h> | |
14 | #include <log.h> | |
15 | #include <asm/cache.h> | |
16 | #include <asm/io.h> | |
17 | #include <linux/delay.h> | |
18 | #include <linux/errno.h> | |
19 | ||
20 | #define I2C_RS_TRANSFER BIT(4) | |
21 | #define I2C_HS_NACKERR BIT(2) | |
22 | #define I2C_ACKERR BIT(1) | |
23 | #define I2C_TRANSAC_COMP BIT(0) | |
24 | #define I2C_TRANSAC_START BIT(0) | |
25 | #define I2C_RS_MUL_CNFG BIT(15) | |
26 | #define I2C_RS_MUL_TRIG BIT(14) | |
27 | #define I2C_DCM_DISABLE 0x0000 | |
28 | #define I2C_IO_CONFIG_OPEN_DRAIN 0x0003 | |
29 | #define I2C_IO_CONFIG_PUSH_PULL 0x0000 | |
30 | #define I2C_SOFT_RST 0x0001 | |
31 | #define I2C_FIFO_ADDR_CLR 0x0001 | |
32 | #define I2C_DELAY_LEN 0x0002 | |
33 | #define I2C_ST_START_CON 0x8001 | |
34 | #define I2C_FS_START_CON 0x1800 | |
35 | #define I2C_TIME_CLR_VALUE 0x0000 | |
36 | #define I2C_TIME_DEFAULT_VALUE 0x0003 | |
37 | #define I2C_WRRD_TRANAC_VALUE 0x0002 | |
38 | #define I2C_RD_TRANAC_VALUE 0x0001 | |
39 | ||
40 | #define I2C_DMA_CON_TX 0x0000 | |
41 | #define I2C_DMA_CON_RX 0x0001 | |
42 | #define I2C_DMA_START_EN 0x0001 | |
43 | #define I2C_DMA_INT_FLAG_NONE 0x0000 | |
44 | #define I2C_DMA_CLR_FLAG 0x0000 | |
45 | #define I2C_DMA_TX_RX 0x0000 | |
46 | #define I2C_DMA_HARD_RST 0x0002 | |
47 | ||
48 | #define MAX_ST_MODE_SPEED 100000 | |
49 | #define MAX_FS_MODE_SPEED 400000 | |
50 | #define MAX_HS_MODE_SPEED 3400000 | |
51 | #define MAX_SAMPLE_CNT_DIV 8 | |
52 | #define MAX_STEP_CNT_DIV 64 | |
53 | #define MAX_HS_STEP_CNT_DIV 8 | |
54 | #define I2C_DEFAULT_CLK_DIV 4 | |
55 | ||
56 | #define MAX_I2C_ADDR 0x7f | |
57 | #define MAX_I2C_LEN 0xff | |
58 | #define TRANS_ADDR_ONLY BIT(8) | |
59 | #define TRANSFER_TIMEOUT 50000 /* us */ | |
60 | #define I2C_FIFO_STAT1_MASK 0x001f | |
61 | #define TIMING_SAMPLE_OFFSET 8 | |
62 | #define HS_SAMPLE_OFFSET 12 | |
63 | #define HS_STEP_OFFSET 8 | |
64 | ||
65 | #define I2C_CONTROL_WRAPPER BIT(0) | |
66 | #define I2C_CONTROL_RS BIT(1) | |
67 | #define I2C_CONTROL_DMA_EN BIT(2) | |
68 | #define I2C_CONTROL_CLK_EXT_EN BIT(3) | |
69 | #define I2C_CONTROL_DIR_CHANGE BIT(4) | |
70 | #define I2C_CONTROL_ACKERR_DET_EN BIT(5) | |
71 | #define I2C_CONTROL_TRANSFER_LEN_CHANGE BIT(6) | |
72 | #define I2C_CONTROL_DMAACK BIT(8) | |
73 | #define I2C_CONTROL_ASYNC BIT(9) | |
74 | ||
75 | #define I2C_MASTER_WR BIT(0) | |
76 | #define I2C_MASTER_RD BIT(1) | |
77 | #define I2C_MASTER_WRRD (I2C_MASTER_WR | I2C_MASTER_RD) | |
78 | ||
79 | enum I2C_REGS_OFFSET { | |
80 | REG_PORT, | |
81 | REG_SLAVE_ADDR, | |
82 | REG_INTR_MASK, | |
83 | REG_INTR_STAT, | |
84 | REG_CONTROL, | |
85 | REG_TRANSFER_LEN, | |
86 | REG_TRANSAC_LEN, | |
87 | REG_DELAY_LEN, | |
88 | REG_TIMING, | |
89 | REG_START, | |
90 | REG_EXT_CONF, | |
91 | REG_FIFO_STAT1, | |
92 | REG_LTIMING, | |
93 | REG_FIFO_STAT, | |
94 | REG_FIFO_THRESH, | |
95 | REG_FIFO_ADDR_CLR, | |
96 | REG_IO_CONFIG, | |
97 | REG_RSV_DEBUG, | |
98 | REG_HS, | |
99 | REG_SOFTRESET, | |
100 | REG_DCM_EN, | |
101 | REG_PATH_DIR, | |
102 | REG_DEBUGSTAT, | |
103 | REG_DEBUGCTRL, | |
104 | REG_TRANSFER_LEN_AUX, | |
105 | REG_CLOCK_DIV, | |
106 | REG_SCL_HL_RATIO, | |
107 | REG_SCL_HS_HL_RATIO, | |
108 | REG_SCL_MIS_COMP_POINT, | |
109 | REG_STA_STOP_AC_TIME, | |
110 | REG_HS_STA_STOP_AC_TIME, | |
111 | REG_DATA_TIME, | |
112 | }; | |
113 | ||
114 | enum DMA_REGS_OFFSET { | |
115 | REG_INT_FLAG = 0x0, | |
116 | REG_INT_EN = 0x04, | |
117 | REG_EN = 0x08, | |
118 | REG_RST = 0x0c, | |
119 | REG_CON = 0x18, | |
120 | REG_TX_MEM_ADDR = 0x1c, | |
121 | REG_RX_MEM_ADDR = 0x20, | |
122 | REG_TX_LEN = 0x24, | |
123 | REG_RX_LEN = 0x28, | |
124 | }; | |
125 | ||
126 | static const uint mt_i2c_regs_v1[] = { | |
127 | [REG_PORT] = 0x0, | |
128 | [REG_SLAVE_ADDR] = 0x4, | |
129 | [REG_INTR_MASK] = 0x8, | |
130 | [REG_INTR_STAT] = 0xc, | |
131 | [REG_CONTROL] = 0x10, | |
132 | [REG_TRANSFER_LEN] = 0x14, | |
133 | [REG_TRANSAC_LEN] = 0x18, | |
134 | [REG_DELAY_LEN] = 0x1c, | |
135 | [REG_TIMING] = 0x20, | |
136 | [REG_START] = 0x24, | |
137 | [REG_EXT_CONF] = 0x28, | |
138 | [REG_FIFO_STAT1] = 0x2c, | |
139 | [REG_FIFO_STAT] = 0x30, | |
140 | [REG_FIFO_THRESH] = 0x34, | |
141 | [REG_FIFO_ADDR_CLR] = 0x38, | |
142 | [REG_IO_CONFIG] = 0x40, | |
143 | [REG_RSV_DEBUG] = 0x44, | |
144 | [REG_HS] = 0x48, | |
145 | [REG_SOFTRESET] = 0x50, | |
146 | [REG_SOFTRESET] = 0x50, | |
147 | [REG_DCM_EN] = 0x54, | |
148 | [REG_DEBUGSTAT] = 0x64, | |
149 | [REG_DEBUGCTRL] = 0x68, | |
150 | [REG_TRANSFER_LEN_AUX] = 0x6c, | |
151 | [REG_CLOCK_DIV] = 0x70, | |
152 | [REG_SCL_HL_RATIO] = 0x74, | |
153 | [REG_SCL_HS_HL_RATIO] = 0x78, | |
154 | [REG_SCL_MIS_COMP_POINT] = 0x7c, | |
155 | [REG_STA_STOP_AC_TIME] = 0x80, | |
156 | [REG_HS_STA_STOP_AC_TIME] = 0x84, | |
157 | [REG_DATA_TIME] = 0x88, | |
158 | }; | |
159 | ||
160 | static const uint mt_i2c_regs_v2[] = { | |
161 | [REG_PORT] = 0x0, | |
162 | [REG_SLAVE_ADDR] = 0x4, | |
163 | [REG_INTR_MASK] = 0x8, | |
164 | [REG_INTR_STAT] = 0xc, | |
165 | [REG_CONTROL] = 0x10, | |
166 | [REG_TRANSFER_LEN] = 0x14, | |
167 | [REG_TRANSAC_LEN] = 0x18, | |
168 | [REG_DELAY_LEN] = 0x1c, | |
169 | [REG_TIMING] = 0x20, | |
170 | [REG_START] = 0x24, | |
171 | [REG_EXT_CONF] = 0x28, | |
172 | [REG_LTIMING] = 0x2c, | |
173 | [REG_HS] = 0x30, | |
174 | [REG_IO_CONFIG] = 0x34, | |
175 | [REG_FIFO_ADDR_CLR] = 0x38, | |
176 | [REG_TRANSFER_LEN_AUX] = 0x44, | |
177 | [REG_CLOCK_DIV] = 0x48, | |
178 | [REG_SOFTRESET] = 0x50, | |
179 | [REG_DEBUGSTAT] = 0xe0, | |
180 | [REG_DEBUGCTRL] = 0xe8, | |
181 | [REG_FIFO_STAT] = 0xf4, | |
182 | [REG_FIFO_THRESH] = 0xf8, | |
183 | [REG_DCM_EN] = 0xf88, | |
184 | }; | |
185 | ||
7fa40df4 WG |
186 | static const uint mt_i2c_regs_v3[] = { |
187 | [REG_PORT] = 0x0, | |
188 | [REG_INTR_MASK] = 0x8, | |
189 | [REG_INTR_STAT] = 0xc, | |
190 | [REG_CONTROL] = 0x10, | |
191 | [REG_TRANSFER_LEN] = 0x14, | |
192 | [REG_TRANSAC_LEN] = 0x18, | |
193 | [REG_DELAY_LEN] = 0x1c, | |
194 | [REG_TIMING] = 0x20, | |
195 | [REG_START] = 0x24, | |
196 | [REG_EXT_CONF] = 0x28, | |
197 | [REG_LTIMING] = 0x2c, | |
198 | [REG_HS] = 0x30, | |
199 | [REG_IO_CONFIG] = 0x34, | |
200 | [REG_FIFO_ADDR_CLR] = 0x38, | |
201 | [REG_TRANSFER_LEN_AUX] = 0x44, | |
202 | [REG_CLOCK_DIV] = 0x48, | |
203 | [REG_SOFTRESET] = 0x50, | |
204 | [REG_SLAVE_ADDR] = 0x94, | |
205 | [REG_DEBUGSTAT] = 0xe4, | |
206 | [REG_DEBUGCTRL] = 0xe8, | |
207 | [REG_FIFO_STAT] = 0xf4, | |
208 | [REG_FIFO_THRESH] = 0xf8, | |
209 | [REG_DCM_EN] = 0xf88, | |
210 | }; | |
211 | ||
9ad71f63 WG |
212 | struct mtk_i2c_soc_data { |
213 | const uint *regs; | |
214 | uint dma_sync: 1; | |
7fa40df4 | 215 | uint ltiming_adjust: 1; |
9ad71f63 WG |
216 | }; |
217 | ||
218 | struct mtk_i2c_priv { | |
219 | /* set in i2c probe */ | |
220 | void __iomem *base; /* i2c base addr */ | |
221 | void __iomem *pdmabase; /* dma base address*/ | |
222 | struct clk clk_main; /* main clock for i2c bus */ | |
223 | struct clk clk_dma; /* DMA clock for i2c via DMA */ | |
72d01e43 CM |
224 | struct clk clk_arb; /* DMA clock for i2c ARB */ |
225 | struct clk clk_pmic; /* DMA clock for i2c PMIC */ | |
9ad71f63 WG |
226 | const struct mtk_i2c_soc_data *soc_data; /* Compatible data for different IC */ |
227 | int op; /* operation mode */ | |
228 | bool zero_len; /* Only transfer slave address, no data */ | |
229 | bool pushpull; /* push pull mode or open drain mode */ | |
230 | bool filter_msg; /* filter msg error log */ | |
231 | bool auto_restart; /* restart mode */ | |
232 | bool ignore_restart_irq; /* ignore restart IRQ */ | |
233 | uint speed; /* i2c speed, unit: hz */ | |
234 | }; | |
235 | ||
236 | static inline void i2c_writel(struct mtk_i2c_priv *priv, uint reg, uint value) | |
237 | { | |
238 | u32 offset = priv->soc_data->regs[reg]; | |
239 | ||
240 | writel(value, priv->base + offset); | |
241 | } | |
242 | ||
243 | static inline uint i2c_readl(struct mtk_i2c_priv *priv, uint offset) | |
244 | { | |
245 | return readl(priv->base + priv->soc_data->regs[offset]); | |
246 | } | |
247 | ||
248 | static int mtk_i2c_clk_enable(struct mtk_i2c_priv *priv) | |
249 | { | |
250 | int ret; | |
251 | ||
252 | ret = clk_enable(&priv->clk_main); | |
253 | if (ret) | |
254 | return log_msg_ret("enable clk_main", ret); | |
255 | ||
256 | ret = clk_enable(&priv->clk_dma); | |
257 | if (ret) | |
258 | return log_msg_ret("enable clk_dma", ret); | |
259 | ||
72d01e43 CM |
260 | if (priv->clk_arb.dev) { |
261 | ret = clk_enable(&priv->clk_arb); | |
262 | if (ret) | |
263 | return log_msg_ret("enable clk_arb", ret); | |
264 | } | |
265 | ||
266 | if (priv->clk_pmic.dev) { | |
267 | ret = clk_enable(&priv->clk_pmic); | |
268 | if (ret) | |
269 | return log_msg_ret("enable clk_pmic", ret); | |
270 | } | |
271 | ||
9ad71f63 WG |
272 | return 0; |
273 | } | |
274 | ||
275 | static int mtk_i2c_clk_disable(struct mtk_i2c_priv *priv) | |
276 | { | |
277 | int ret; | |
278 | ||
72d01e43 CM |
279 | if (priv->clk_pmic.dev) { |
280 | ret = clk_disable(&priv->clk_pmic); | |
281 | if (ret) | |
282 | return log_msg_ret("disable clk_pmic", ret); | |
283 | } | |
284 | ||
285 | if (priv->clk_arb.dev) { | |
286 | ret = clk_disable(&priv->clk_arb); | |
287 | if (ret) | |
288 | return log_msg_ret("disable clk_arb", ret); | |
289 | } | |
290 | ||
9ad71f63 WG |
291 | ret = clk_disable(&priv->clk_dma); |
292 | if (ret) | |
293 | return log_msg_ret("disable clk_dma", ret); | |
294 | ||
295 | ret = clk_disable(&priv->clk_main); | |
296 | if (ret) | |
297 | return log_msg_ret("disable clk_main", ret); | |
298 | ||
299 | return 0; | |
300 | } | |
301 | ||
302 | static void mtk_i2c_init_hw(struct mtk_i2c_priv *priv) | |
303 | { | |
304 | uint control_reg; | |
305 | ||
306 | writel(I2C_DMA_HARD_RST, priv->pdmabase + REG_RST); | |
307 | writel(I2C_DMA_CLR_FLAG, priv->pdmabase + REG_RST); | |
308 | i2c_writel(priv, REG_SOFTRESET, I2C_SOFT_RST); | |
309 | /* set ioconfig */ | |
310 | if (priv->pushpull) | |
311 | i2c_writel(priv, REG_IO_CONFIG, I2C_IO_CONFIG_PUSH_PULL); | |
312 | else | |
313 | i2c_writel(priv, REG_IO_CONFIG, I2C_IO_CONFIG_OPEN_DRAIN); | |
314 | ||
315 | i2c_writel(priv, REG_DCM_EN, I2C_DCM_DISABLE); | |
316 | control_reg = I2C_CONTROL_ACKERR_DET_EN | I2C_CONTROL_CLK_EXT_EN; | |
317 | if (priv->soc_data->dma_sync) | |
318 | control_reg |= I2C_CONTROL_DMAACK | I2C_CONTROL_ASYNC; | |
319 | i2c_writel(priv, REG_CONTROL, control_reg); | |
320 | i2c_writel(priv, REG_DELAY_LEN, I2C_DELAY_LEN); | |
321 | } | |
322 | ||
323 | /* | |
324 | * Calculate i2c port speed | |
325 | * | |
326 | * Hardware design: | |
327 | * i2c_bus_freq = parent_clk / (clock_div * 2 * sample_cnt * step_cnt) | |
328 | * clock_div: fixed in hardware, but may be various in different SoCs | |
329 | * | |
330 | * The calculation want to pick the highest bus frequency that is still | |
331 | * less than or equal to target_speed. The calculation try to get | |
332 | * sample_cnt and step_cn | |
333 | * @param[in] | |
334 | * clk_src: i2c clock source | |
335 | * @param[out] | |
336 | * timing_step_cnt: step cnt calculate result | |
337 | * @param[out] | |
338 | * timing_sample_cnt: sample cnt calculate result | |
339 | * @return | |
340 | * 0, set speed successfully. | |
341 | * -EINVAL, Unsupported speed. | |
342 | */ | |
343 | static int mtk_i2c_calculate_speed(uint clk_src, | |
344 | uint target_speed, | |
345 | uint *timing_step_cnt, | |
346 | uint *timing_sample_cnt) | |
347 | { | |
348 | uint base_sample_cnt = MAX_SAMPLE_CNT_DIV; | |
349 | uint base_step_cnt; | |
350 | uint max_step_cnt; | |
351 | uint sample_cnt; | |
352 | uint step_cnt; | |
353 | uint opt_div; | |
354 | uint best_mul; | |
355 | uint cnt_mul; | |
356 | ||
357 | if (target_speed > MAX_HS_MODE_SPEED) | |
358 | target_speed = MAX_HS_MODE_SPEED; | |
359 | ||
360 | if (target_speed > MAX_FS_MODE_SPEED) | |
361 | max_step_cnt = MAX_HS_STEP_CNT_DIV; | |
362 | else | |
363 | max_step_cnt = MAX_STEP_CNT_DIV; | |
364 | ||
365 | base_step_cnt = max_step_cnt; | |
366 | /* Find the best combination */ | |
367 | opt_div = DIV_ROUND_UP(clk_src >> 1, target_speed); | |
368 | best_mul = MAX_SAMPLE_CNT_DIV * max_step_cnt; | |
369 | ||
370 | /* | |
371 | * Search for the best pair (sample_cnt, step_cnt) with | |
372 | * 0 < sample_cnt < MAX_SAMPLE_CNT_DIV | |
373 | * 0 < step_cnt < max_step_cnt | |
374 | * sample_cnt * step_cnt >= opt_div | |
375 | * optimizing for sample_cnt * step_cnt being minimal | |
376 | */ | |
377 | for (sample_cnt = 1; sample_cnt <= MAX_SAMPLE_CNT_DIV; sample_cnt++) { | |
378 | step_cnt = DIV_ROUND_UP(opt_div, sample_cnt); | |
379 | cnt_mul = step_cnt * sample_cnt; | |
380 | if (step_cnt > max_step_cnt) | |
381 | continue; | |
382 | ||
383 | if (cnt_mul < best_mul) { | |
384 | best_mul = cnt_mul; | |
385 | base_sample_cnt = sample_cnt; | |
386 | base_step_cnt = step_cnt; | |
387 | if (best_mul == opt_div) | |
388 | break; | |
389 | } | |
390 | } | |
391 | ||
392 | sample_cnt = base_sample_cnt; | |
393 | step_cnt = base_step_cnt; | |
394 | ||
395 | if ((clk_src / (2 * sample_cnt * step_cnt)) > target_speed) { | |
396 | /* | |
397 | * In this case, hardware can't support such | |
398 | * low i2c_bus_freq | |
399 | */ | |
400 | debug("Unsupported speed(%uhz)\n", target_speed); | |
401 | return log_msg_ret("calculate speed", -EINVAL); | |
402 | } | |
403 | ||
404 | *timing_step_cnt = step_cnt - 1; | |
405 | *timing_sample_cnt = sample_cnt - 1; | |
406 | ||
407 | return 0; | |
408 | } | |
409 | ||
410 | /* | |
411 | * mtk_i2c_set_speed | |
412 | * | |
413 | * @par Description | |
414 | * Calculate i2c speed and write sample_cnt, step_cnt to TIMING register. | |
415 | * @param[in] | |
416 | * dev: udevice pointer, struct udevice contains i2c source clock, | |
417 | * clock divide and speed. | |
418 | * @return | |
419 | * 0, set speed successfully.\n | |
420 | * error code from mtk_i2c_calculate_speed(). | |
421 | */ | |
422 | static int mtk_i2c_set_speed(struct udevice *dev, uint speed) | |
423 | { | |
424 | struct mtk_i2c_priv *priv = dev_get_priv(dev); | |
425 | uint high_speed_reg; | |
426 | uint sample_cnt; | |
427 | uint timing_reg; | |
428 | uint step_cnt; | |
429 | uint clk_src; | |
430 | int ret = 0; | |
431 | ||
432 | priv->speed = speed; | |
433 | if (mtk_i2c_clk_enable(priv)) | |
434 | return log_msg_ret("set_speed enable clk", -1); | |
435 | ||
436 | clk_src = clk_get_rate(&priv->clk_main) / I2C_DEFAULT_CLK_DIV; | |
437 | i2c_writel(priv, REG_CLOCK_DIV, (I2C_DEFAULT_CLK_DIV - 1)); | |
438 | if (priv->speed > MAX_FS_MODE_SPEED) { | |
439 | /* Set master code speed register */ | |
440 | ret = mtk_i2c_calculate_speed(clk_src, MAX_FS_MODE_SPEED, | |
441 | &step_cnt, &sample_cnt); | |
442 | if (ret < 0) | |
443 | goto exit; | |
444 | ||
445 | timing_reg = (sample_cnt << TIMING_SAMPLE_OFFSET) | step_cnt; | |
446 | i2c_writel(priv, REG_TIMING, timing_reg); | |
447 | /* Set the high speed mode register */ | |
448 | ret = mtk_i2c_calculate_speed(clk_src, priv->speed, | |
449 | &step_cnt, &sample_cnt); | |
450 | if (ret < 0) | |
451 | goto exit; | |
452 | ||
453 | high_speed_reg = I2C_TIME_DEFAULT_VALUE | | |
454 | (sample_cnt << HS_SAMPLE_OFFSET) | | |
455 | (step_cnt << HS_STEP_OFFSET); | |
456 | i2c_writel(priv, REG_HS, high_speed_reg); | |
7fa40df4 WG |
457 | if (priv->soc_data->ltiming_adjust) { |
458 | timing_reg = (sample_cnt << 12) | (step_cnt << 9); | |
459 | i2c_writel(priv, REG_LTIMING, timing_reg); | |
460 | } | |
9ad71f63 WG |
461 | } else { |
462 | ret = mtk_i2c_calculate_speed(clk_src, priv->speed, | |
463 | &step_cnt, &sample_cnt); | |
464 | if (ret < 0) | |
465 | goto exit; | |
466 | ||
467 | timing_reg = (sample_cnt << TIMING_SAMPLE_OFFSET) | step_cnt; | |
468 | /* Disable the high speed transaction */ | |
469 | high_speed_reg = I2C_TIME_CLR_VALUE; | |
470 | i2c_writel(priv, REG_TIMING, timing_reg); | |
471 | i2c_writel(priv, REG_HS, high_speed_reg); | |
7fa40df4 WG |
472 | if (priv->soc_data->ltiming_adjust) { |
473 | timing_reg = (sample_cnt << 6) | step_cnt; | |
474 | i2c_writel(priv, REG_LTIMING, timing_reg); | |
475 | } | |
9ad71f63 | 476 | } |
7fa40df4 | 477 | |
9ad71f63 WG |
478 | exit: |
479 | if (mtk_i2c_clk_disable(priv)) | |
480 | return log_msg_ret("set_speed disable clk", -1); | |
481 | ||
482 | return ret; | |
483 | } | |
484 | ||
485 | /* | |
486 | * mtk_i2c_do_transfer | |
487 | * | |
488 | * @par Description | |
489 | * Configure i2c register and trigger transfer. | |
490 | * @param[in] | |
491 | * priv: mtk_i2cmtk_i2c_priv pointer, struct mtk_i2c_priv contains register base\n | |
492 | * address, operation mode, interrupt status and i2c driver data. | |
493 | * @param[in] | |
494 | * msgs: i2c_msg pointer, struct i2c_msg contains slave\n | |
495 | * address, operation mode, msg length and data buffer. | |
496 | * @param[in] | |
497 | * num: i2c_msg number. | |
498 | * @param[in] | |
499 | * left_num: left i2c_msg number. | |
500 | * @return | |
501 | * 0, i2c transfer successfully.\n | |
502 | * -ETIMEDOUT, i2c transfer timeout.\n | |
503 | * -EREMOTEIO, i2c transfer ack error. | |
504 | */ | |
505 | static int mtk_i2c_do_transfer(struct mtk_i2c_priv *priv, | |
506 | struct i2c_msg *msgs, | |
507 | int num, int left_num) | |
508 | { | |
509 | struct i2c_msg *msg_rx = NULL; | |
510 | uint restart_flag = 0; | |
511 | uint trans_error = 0; | |
512 | uint irq_stat = 0; | |
513 | uint tmo_poll = 0; | |
514 | uint control_reg; | |
515 | bool tmo = false; | |
516 | uint start_reg; | |
517 | uint addr_reg; | |
518 | int ret = 0; | |
519 | ||
520 | if (priv->auto_restart) | |
521 | restart_flag = I2C_RS_TRANSFER; | |
522 | ||
523 | control_reg = i2c_readl(priv, REG_CONTROL) & | |
524 | ~(I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS); | |
525 | ||
526 | if (priv->speed > MAX_FS_MODE_SPEED || num > 1) | |
527 | control_reg |= I2C_CONTROL_RS; | |
528 | ||
529 | if (priv->op == I2C_MASTER_WRRD) | |
530 | control_reg |= I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS; | |
531 | ||
532 | control_reg |= I2C_CONTROL_DMA_EN; | |
533 | i2c_writel(priv, REG_CONTROL, control_reg); | |
534 | ||
535 | /* set start condition */ | |
536 | if (priv->speed <= MAX_ST_MODE_SPEED) | |
537 | i2c_writel(priv, REG_EXT_CONF, I2C_ST_START_CON); | |
538 | else | |
539 | i2c_writel(priv, REG_EXT_CONF, I2C_FS_START_CON); | |
540 | ||
541 | addr_reg = msgs->addr << 1; | |
542 | if (priv->op == I2C_MASTER_RD) | |
543 | addr_reg |= I2C_M_RD; | |
544 | if (priv->zero_len) | |
545 | i2c_writel(priv, REG_SLAVE_ADDR, addr_reg | TRANS_ADDR_ONLY); | |
546 | else | |
547 | i2c_writel(priv, REG_SLAVE_ADDR, addr_reg); | |
548 | ||
549 | /* clear interrupt status */ | |
550 | i2c_writel(priv, REG_INTR_STAT, restart_flag | I2C_HS_NACKERR | | |
551 | I2C_ACKERR | I2C_TRANSAC_COMP); | |
552 | i2c_writel(priv, REG_FIFO_ADDR_CLR, I2C_FIFO_ADDR_CLR); | |
553 | ||
554 | /* enable interrupt */ | |
555 | i2c_writel(priv, REG_INTR_MASK, restart_flag | I2C_HS_NACKERR | | |
556 | I2C_ACKERR | I2C_TRANSAC_COMP); | |
557 | ||
558 | /* set transfer and transaction len */ | |
559 | if (priv->op == I2C_MASTER_WRRD) { | |
560 | i2c_writel(priv, REG_TRANSFER_LEN, msgs->len); | |
561 | i2c_writel(priv, REG_TRANSFER_LEN_AUX, (msgs + 1)->len); | |
562 | i2c_writel(priv, REG_TRANSAC_LEN, I2C_WRRD_TRANAC_VALUE); | |
563 | } else { | |
564 | i2c_writel(priv, REG_TRANSFER_LEN, msgs->len); | |
565 | i2c_writel(priv, REG_TRANSAC_LEN, num); | |
566 | } | |
567 | ||
568 | /* Clear DMA interrupt flag */ | |
569 | writel(I2C_DMA_INT_FLAG_NONE, priv->pdmabase + REG_INT_FLAG); | |
570 | ||
571 | /* Flush cache for first msg */ | |
572 | flush_cache((ulong)msgs->buf, msgs->len); | |
573 | ||
574 | /* | |
575 | * prepare buffer data to start transfer | |
576 | * three cases here: read, write, write then read | |
577 | */ | |
578 | if (priv->op & I2C_MASTER_WR) { | |
579 | /* Set DMA direction TX (w/ or w/o RX) */ | |
580 | writel(I2C_DMA_CON_TX, priv->pdmabase + REG_CON); | |
581 | ||
582 | /* Write the tx buffer address to dma register */ | |
583 | writel((ulong)msgs->buf, priv->pdmabase + REG_TX_MEM_ADDR); | |
584 | /* Write the tx length to dma register */ | |
585 | writel(msgs->len, priv->pdmabase + REG_TX_LEN); | |
586 | ||
587 | if (priv->op & I2C_MASTER_RD) { | |
588 | /* write then read */ | |
589 | msg_rx = msgs + 1; | |
590 | ||
591 | /* Flush cache for second msg */ | |
592 | flush_cache((ulong)msg_rx->buf, msg_rx->len); | |
593 | } | |
594 | } | |
595 | ||
596 | if (priv->op & I2C_MASTER_RD) { | |
597 | if (!msg_rx) { | |
598 | /* Set DMA direction RX */ | |
599 | writel(I2C_DMA_CON_RX, priv->pdmabase + REG_CON); | |
600 | ||
601 | msg_rx = msgs; | |
602 | } | |
603 | ||
604 | /* Write the rx buffer address to dma register */ | |
605 | writel((ulong)msg_rx->buf, priv->pdmabase + REG_RX_MEM_ADDR); | |
606 | /* Write the rx length to dma register */ | |
607 | writel(msg_rx->len, priv->pdmabase + REG_RX_LEN); | |
608 | } | |
609 | ||
610 | writel(I2C_DMA_START_EN, priv->pdmabase + REG_EN); | |
611 | ||
612 | if (!priv->auto_restart) { | |
613 | start_reg = I2C_TRANSAC_START; | |
614 | } else { | |
615 | start_reg = I2C_TRANSAC_START | I2C_RS_MUL_TRIG; | |
616 | if (left_num >= 1) | |
617 | start_reg |= I2C_RS_MUL_CNFG; | |
618 | } | |
619 | i2c_writel(priv, REG_START, start_reg); | |
620 | ||
621 | for (;;) { | |
622 | irq_stat = i2c_readl(priv, REG_INTR_STAT); | |
623 | ||
624 | /* ignore the first restart irq after the master code */ | |
625 | if (priv->ignore_restart_irq && (irq_stat & restart_flag)) { | |
626 | priv->ignore_restart_irq = false; | |
627 | irq_stat = 0; | |
628 | i2c_writel(priv, REG_START, I2C_RS_MUL_CNFG | | |
629 | I2C_RS_MUL_TRIG | I2C_TRANSAC_START); | |
630 | } | |
631 | ||
632 | if (irq_stat & (I2C_TRANSAC_COMP | restart_flag)) { | |
633 | tmo = false; | |
634 | if (irq_stat & (I2C_HS_NACKERR | I2C_ACKERR)) | |
635 | trans_error = 1; | |
636 | ||
637 | break; | |
638 | } | |
639 | udelay(1); | |
640 | if (tmo_poll++ >= TRANSFER_TIMEOUT) { | |
641 | tmo = true; | |
642 | break; | |
643 | } | |
644 | } | |
645 | ||
646 | /* clear interrupt mask */ | |
647 | i2c_writel(priv, REG_INTR_MASK, ~(restart_flag | I2C_HS_NACKERR | | |
648 | I2C_ACKERR | I2C_TRANSAC_COMP)); | |
649 | ||
8cf61051 | 650 | if (tmo || trans_error != 0) { |
9ad71f63 WG |
651 | if (tmo) { |
652 | ret = -ETIMEDOUT; | |
653 | if (!priv->filter_msg) | |
654 | debug("I2C timeout! addr: 0x%x,\n", msgs->addr); | |
655 | } else { | |
656 | ret = -EREMOTEIO; | |
657 | if (!priv->filter_msg) | |
658 | debug("I2C ACKERR! addr: 0x%x,IRQ:0x%x\n", | |
659 | msgs->addr, irq_stat); | |
660 | } | |
661 | mtk_i2c_init_hw(priv); | |
662 | } | |
663 | ||
664 | return ret; | |
665 | } | |
666 | ||
667 | /* | |
668 | * mtk_i2c_transfer | |
669 | * | |
670 | * @par Description | |
671 | * Common i2c transfer API. Set i2c transfer mode according to i2c_msg\n | |
672 | * information, then call mtk_i2c_do_transfer() to configure i2c register\n | |
673 | * and trigger transfer. | |
674 | * @param[in] | |
675 | * dev: udevice pointer, struct udevice contains struct mtk_i2c_priv, \n | |
676 | * struct mtk_i2c_priv contains register base\n | |
677 | * address, operation mode, interrupt status and i2c driver data. | |
678 | * @param[in] | |
679 | * msgs: i2c_msg pointer, struct i2c_msg contains slave\n | |
680 | * address, operation mode, msg length and data buffer. | |
681 | * @param[in] | |
682 | * num: i2c_msg number. | |
683 | * @return | |
684 | * i2c_msg number, i2c transfer successfully.\n | |
685 | * -EINVAL, msg length is more than 16\n | |
686 | * use DMA MODE or slave address more than 0x7f.\n | |
687 | * error code from mtk_i2c_init_base().\n | |
688 | * error code from mtk_i2c_set_speed().\n | |
689 | * error code from mtk_i2c_do_transfer(). | |
690 | */ | |
691 | static int mtk_i2c_transfer(struct udevice *dev, struct i2c_msg *msg, | |
692 | int nmsgs) | |
693 | { | |
694 | struct mtk_i2c_priv *priv = dev_get_priv(dev); | |
695 | int left_num; | |
696 | uint num_cnt; | |
697 | int ret; | |
698 | ||
699 | priv->auto_restart = true; | |
700 | left_num = nmsgs; | |
701 | if (mtk_i2c_clk_enable(priv)) | |
702 | return log_msg_ret("transfer enable clk", -1); | |
703 | ||
704 | for (num_cnt = 0; num_cnt < nmsgs; num_cnt++) { | |
705 | if (((msg + num_cnt)->addr) > MAX_I2C_ADDR) { | |
706 | ret = -EINVAL; | |
707 | goto err_exit; | |
708 | } | |
709 | if ((msg + num_cnt)->len > MAX_I2C_LEN) { | |
710 | ret = -EINVAL; | |
711 | goto err_exit; | |
712 | } | |
713 | } | |
714 | ||
715 | /* check if we can skip restart and optimize using WRRD mode */ | |
716 | if (priv->auto_restart && nmsgs == 2) { | |
717 | if (!(msg[0].flags & I2C_M_RD) && (msg[1].flags & I2C_M_RD) && | |
718 | msg[0].addr == msg[1].addr) { | |
719 | priv->auto_restart = false; | |
720 | } | |
721 | } | |
722 | ||
723 | if (priv->auto_restart && nmsgs >= 2 && priv->speed > MAX_FS_MODE_SPEED) | |
724 | /* ignore the first restart irq after the master code, | |
725 | * otherwise the first transfer will be discarded. | |
726 | */ | |
727 | priv->ignore_restart_irq = true; | |
728 | else | |
729 | priv->ignore_restart_irq = false; | |
730 | ||
731 | while (left_num--) { | |
732 | /* transfer slave address only to support devices detect */ | |
733 | if (!msg->buf) | |
734 | priv->zero_len = true; | |
735 | else | |
736 | priv->zero_len = false; | |
737 | ||
738 | if (msg->flags & I2C_M_RD) | |
739 | priv->op = I2C_MASTER_RD; | |
740 | else | |
741 | priv->op = I2C_MASTER_WR; | |
742 | ||
743 | if (!priv->auto_restart) { | |
744 | if (nmsgs > 1) { | |
745 | /* combined two messages into one transaction */ | |
746 | priv->op = I2C_MASTER_WRRD; | |
747 | left_num--; | |
748 | } | |
749 | } | |
750 | ret = mtk_i2c_do_transfer(priv, msg, nmsgs, left_num); | |
751 | if (ret < 0) | |
752 | goto err_exit; | |
753 | msg++; | |
754 | } | |
755 | ret = 0; | |
756 | ||
757 | err_exit: | |
758 | if (mtk_i2c_clk_disable(priv)) | |
759 | return log_msg_ret("transfer disable clk", -1); | |
760 | ||
761 | return ret; | |
762 | } | |
763 | ||
764 | static int mtk_i2c_of_to_plat(struct udevice *dev) | |
765 | { | |
766 | struct mtk_i2c_priv *priv = dev_get_priv(dev); | |
767 | int ret; | |
768 | ||
769 | priv->base = dev_remap_addr_index(dev, 0); | |
770 | priv->pdmabase = dev_remap_addr_index(dev, 1); | |
771 | ret = clk_get_by_index(dev, 0, &priv->clk_main); | |
772 | if (ret) | |
773 | return log_msg_ret("clk_get_by_index 0", ret); | |
774 | ||
775 | ret = clk_get_by_index(dev, 1, &priv->clk_dma); | |
776 | ||
72d01e43 CM |
777 | /* optional i2c clock */ |
778 | clk_get_by_name(dev, "arb", &priv->clk_arb); | |
779 | clk_get_by_name(dev, "pmic", &priv->clk_pmic); | |
780 | ||
9ad71f63 WG |
781 | return ret; |
782 | } | |
783 | ||
784 | static int mtk_i2c_probe(struct udevice *dev) | |
785 | { | |
786 | struct mtk_i2c_priv *priv = dev_get_priv(dev); | |
787 | ||
788 | priv->soc_data = (struct mtk_i2c_soc_data *)dev_get_driver_data(dev); | |
789 | ||
790 | if (mtk_i2c_clk_enable(priv)) | |
791 | return log_msg_ret("probe enable clk", -1); | |
792 | ||
793 | mtk_i2c_init_hw(priv); | |
9ad71f63 WG |
794 | if (mtk_i2c_clk_disable(priv)) |
795 | return log_msg_ret("probe disable clk", -1); | |
796 | ||
797 | return 0; | |
798 | } | |
799 | ||
800 | static int mtk_i2c_deblock(struct udevice *dev) | |
801 | { | |
802 | struct mtk_i2c_priv *priv = dev_get_priv(dev); | |
803 | ||
804 | if (mtk_i2c_clk_enable(priv)) | |
805 | return log_msg_ret("deblock enable clk", -1); | |
806 | ||
807 | mtk_i2c_init_hw(priv); | |
808 | ||
809 | if (mtk_i2c_clk_disable(priv)) | |
810 | return log_msg_ret("deblock disable clk", -1); | |
811 | ||
812 | return 0; | |
813 | } | |
814 | ||
815 | static const struct mtk_i2c_soc_data mt76xx_soc_data = { | |
816 | .regs = mt_i2c_regs_v1, | |
817 | .dma_sync = 0, | |
7fa40df4 | 818 | .ltiming_adjust = 0, |
9ad71f63 WG |
819 | }; |
820 | ||
821 | static const struct mtk_i2c_soc_data mt7981_soc_data = { | |
7fa40df4 | 822 | .regs = mt_i2c_regs_v3, |
9ad71f63 | 823 | .dma_sync = 1, |
7fa40df4 | 824 | .ltiming_adjust = 1, |
9ad71f63 WG |
825 | }; |
826 | ||
827 | static const struct mtk_i2c_soc_data mt7986_soc_data = { | |
828 | .regs = mt_i2c_regs_v1, | |
829 | .dma_sync = 1, | |
7fa40df4 | 830 | .ltiming_adjust = 0, |
9ad71f63 WG |
831 | }; |
832 | ||
833 | static const struct mtk_i2c_soc_data mt8183_soc_data = { | |
834 | .regs = mt_i2c_regs_v2, | |
835 | .dma_sync = 1, | |
7fa40df4 | 836 | .ltiming_adjust = 0, |
9ad71f63 WG |
837 | }; |
838 | ||
839 | static const struct mtk_i2c_soc_data mt8518_soc_data = { | |
840 | .regs = mt_i2c_regs_v1, | |
841 | .dma_sync = 0, | |
7fa40df4 | 842 | .ltiming_adjust = 0, |
9ad71f63 WG |
843 | }; |
844 | ||
845 | static const struct mtk_i2c_soc_data mt8512_soc_data = { | |
846 | .regs = mt_i2c_regs_v1, | |
847 | .dma_sync = 1, | |
7fa40df4 | 848 | .ltiming_adjust = 0, |
9ad71f63 WG |
849 | }; |
850 | ||
851 | static const struct dm_i2c_ops mtk_i2c_ops = { | |
852 | .xfer = mtk_i2c_transfer, | |
853 | .set_bus_speed = mtk_i2c_set_speed, | |
854 | .deblock = mtk_i2c_deblock, | |
855 | }; | |
856 | ||
857 | static const struct udevice_id mtk_i2c_ids[] = { | |
858 | { | |
859 | .compatible = "mediatek,mt7622-i2c", | |
860 | .data = (ulong)&mt76xx_soc_data, | |
861 | }, { | |
862 | .compatible = "mediatek,mt7623-i2c", | |
863 | .data = (ulong)&mt76xx_soc_data, | |
864 | }, { | |
865 | .compatible = "mediatek,mt7629-i2c", | |
866 | .data = (ulong)&mt76xx_soc_data, | |
867 | }, { | |
868 | .compatible = "mediatek,mt7981-i2c", | |
869 | .data = (ulong)&mt7981_soc_data, | |
870 | }, { | |
871 | .compatible = "mediatek,mt7986-i2c", | |
872 | .data = (ulong)&mt7986_soc_data, | |
873 | }, { | |
874 | .compatible = "mediatek,mt8183-i2c", | |
875 | .data = (ulong)&mt8183_soc_data, | |
876 | }, { | |
877 | .compatible = "mediatek,mt8512-i2c", | |
878 | .data = (ulong)&mt8512_soc_data, | |
879 | }, { | |
880 | .compatible = "mediatek,mt8518-i2c", | |
881 | .data = (ulong)&mt8518_soc_data, | |
882 | } | |
883 | }; | |
884 | ||
885 | U_BOOT_DRIVER(mtk_i2c) = { | |
886 | .name = "mtk_i2c", | |
887 | .id = UCLASS_I2C, | |
888 | .of_match = mtk_i2c_ids, | |
889 | .of_to_plat = mtk_i2c_of_to_plat, | |
890 | .probe = mtk_i2c_probe, | |
891 | .priv_auto = sizeof(struct mtk_i2c_priv), | |
892 | .ops = &mtk_i2c_ops, | |
893 | }; |