1 #include "bflb_i2c.h"
2 #include "bflb_clock.h"
3 #include "hardware/i2c_reg.h"
4
5 #define PUT_UINT32_LE(field, value) \
6 do { \
7 (field)[0] = (uint8_t)((value) >> 0); \
8 (field)[1] = (uint8_t)((value) >> 8); \
9 (field)[2] = (uint8_t)((value) >> 16); \
10 (field)[3] = (uint8_t)((value) >> 24); \
11 } while (0)
12
bflb_i2c_addr_config(struct bflb_device_s * dev,uint16_t slaveaddr,uint16_t subaddr,uint8_t subaddr_size,bool is_addr_10bit)13 static void bflb_i2c_addr_config(struct bflb_device_s *dev, uint16_t slaveaddr, uint16_t subaddr, uint8_t subaddr_size, bool is_addr_10bit)
14 {
15 uint32_t regval;
16 uint32_t reg_base;
17
18 reg_base = dev->reg_base;
19
20 regval = getreg32(reg_base + I2C_CONFIG_OFFSET);
21
22 if (subaddr_size > 0) {
23 regval |= I2C_CR_I2C_SUB_ADDR_EN;
24 regval &= ~I2C_CR_I2C_SUB_ADDR_BC_MASK;
25 regval |= ((subaddr_size - 1) << I2C_CR_I2C_SUB_ADDR_BC_SHIFT);
26 } else {
27 regval &= ~I2C_CR_I2C_SUB_ADDR_EN;
28 }
29
30 regval &= ~I2C_CR_I2C_SLV_ADDR_MASK;
31 regval |= (slaveaddr << I2C_CR_I2C_SLV_ADDR_SHIFT);
32 #if !defined(BL602) && !defined(BL702)
33 if (is_addr_10bit) {
34 regval |= I2C_CR_I2C_10B_ADDR_EN;
35 } else {
36 regval &= ~I2C_CR_I2C_10B_ADDR_EN;
37 }
38 #endif
39 regval &= ~I2C_CR_I2C_SCL_SYNC_EN;
40 putreg32(subaddr, reg_base + I2C_SUB_ADDR_OFFSET);
41 putreg32(regval, reg_base + I2C_CONFIG_OFFSET);
42 }
43
bflb_i2c_set_dir(struct bflb_device_s * dev,bool is_in)44 static inline void bflb_i2c_set_dir(struct bflb_device_s *dev, bool is_in)
45 {
46 uint32_t regval;
47 uint32_t reg_base;
48
49 reg_base = dev->reg_base;
50
51 regval = getreg32(reg_base + I2C_CONFIG_OFFSET);
52
53 if (is_in) {
54 regval |= I2C_CR_I2C_PKT_DIR;
55 } else {
56 regval &= ~I2C_CR_I2C_PKT_DIR;
57 }
58 putreg32(regval, reg_base + I2C_CONFIG_OFFSET);
59 }
60
bflb_i2c_set_datalen(struct bflb_device_s * dev,uint16_t data_len)61 static inline void bflb_i2c_set_datalen(struct bflb_device_s *dev, uint16_t data_len)
62 {
63 uint32_t regval;
64 uint32_t reg_base;
65
66 reg_base = dev->reg_base;
67
68 regval = getreg32(reg_base + I2C_CONFIG_OFFSET);
69 regval &= ~I2C_CR_I2C_PKT_LEN_MASK;
70 regval |= ((data_len - 1) << I2C_CR_I2C_PKT_LEN_SHIFT) & I2C_CR_I2C_PKT_LEN_MASK;
71 putreg32(regval, reg_base + I2C_CONFIG_OFFSET);
72 }
73
bflb_i2c_set_frequence(struct bflb_device_s * dev,uint32_t freq)74 static void bflb_i2c_set_frequence(struct bflb_device_s *dev, uint32_t freq)
75 {
76 uint32_t regval;
77 uint32_t reg_base;
78 uint32_t phase;
79 uint32_t tmp;
80
81 reg_base = dev->reg_base;
82
83 phase = bflb_clk_get_peripheral_clock(BFLB_DEVICE_TYPE_I2C, dev->idx) / (freq * 4) - 1;
84
85 if (freq > 100000) {
86 tmp = ((phase / 4) / 0.5);
87 } else {
88 tmp = (phase / 4);
89 }
90
91 regval = (phase - tmp) << I2C_CR_I2C_PRD_S_PH_0_SHIFT;
92 regval |= (phase + tmp) << I2C_CR_I2C_PRD_S_PH_1_SHIFT;
93 regval |= (phase) << I2C_CR_I2C_PRD_S_PH_2_SHIFT;
94 regval |= (phase) << I2C_CR_I2C_PRD_S_PH_3_SHIFT;
95
96 putreg32(regval, reg_base + I2C_PRD_START_OFFSET);
97 putreg32(regval, reg_base + I2C_PRD_STOP_OFFSET);
98
99 regval = (phase - tmp) << I2C_CR_I2C_PRD_D_PH_0_SHIFT;
100 regval |= (phase + tmp) << I2C_CR_I2C_PRD_D_PH_1_SHIFT;
101 regval |= (phase + tmp) << I2C_CR_I2C_PRD_D_PH_2_SHIFT;
102 regval |= (phase - tmp) << I2C_CR_I2C_PRD_D_PH_3_SHIFT;
103 putreg32(regval, reg_base + I2C_PRD_DATA_OFFSET);
104 }
105
bflb_i2c_isbusy(struct bflb_device_s * dev)106 static inline bool bflb_i2c_isbusy(struct bflb_device_s *dev)
107 {
108 uint32_t regval;
109 uint32_t reg_base;
110
111 reg_base = dev->reg_base;
112
113 regval = getreg32(reg_base + I2C_BUS_BUSY_OFFSET);
114
115 if (regval & I2C_STS_I2C_BUS_BUSY) {
116 return true;
117 }
118
119 return false;
120 }
121
bflb_i2c_isend(struct bflb_device_s * dev)122 static inline bool bflb_i2c_isend(struct bflb_device_s *dev)
123 {
124 uint32_t regval;
125 uint32_t reg_base;
126
127 reg_base = dev->reg_base;
128
129 regval = getreg32(reg_base + I2C_INT_STS_OFFSET);
130
131 if (regval & I2C_END_INT) {
132 return true;
133 }
134
135 return false;
136 }
137
bflb_i2c_isnak(struct bflb_device_s * dev)138 static inline bool bflb_i2c_isnak(struct bflb_device_s *dev)
139 {
140 uint32_t regval;
141 uint32_t reg_base;
142
143 reg_base = dev->reg_base;
144
145 regval = getreg32(reg_base + I2C_INT_STS_OFFSET);
146
147 if (regval & I2C_NAK_INT) {
148 return true;
149 }
150
151 return false;
152 }
153
bflb_i2c_enable(struct bflb_device_s * dev)154 static inline void bflb_i2c_enable(struct bflb_device_s *dev)
155 {
156 uint32_t regval;
157 uint32_t reg_base;
158
159 reg_base = dev->reg_base;
160
161 regval = getreg32(reg_base + I2C_CONFIG_OFFSET);
162 regval |= I2C_CR_I2C_M_EN;
163 putreg32(regval, reg_base + I2C_CONFIG_OFFSET);
164 }
165
bflb_i2c_disable(struct bflb_device_s * dev)166 static inline void bflb_i2c_disable(struct bflb_device_s *dev)
167 {
168 uint32_t regval;
169 uint32_t reg_base;
170
171 reg_base = dev->reg_base;
172
173 regval = getreg32(reg_base + I2C_CONFIG_OFFSET);
174 regval &= ~I2C_CR_I2C_M_EN;
175 putreg32(regval, reg_base + I2C_CONFIG_OFFSET);
176 /* Clear I2C fifo */
177 regval = getreg32(reg_base + I2C_FIFO_CONFIG_0_OFFSET);
178 regval |= I2C_TX_FIFO_CLR;
179 regval |= I2C_RX_FIFO_CLR;
180 putreg32(regval, reg_base + I2C_FIFO_CONFIG_0_OFFSET);
181 /* Clear I2C interrupt status */
182 regval = getreg32(reg_base + I2C_INT_STS_OFFSET);
183 regval |= I2C_CR_I2C_END_CLR;
184 regval |= I2C_CR_I2C_NAK_CLR;
185 regval |= I2C_CR_I2C_ARB_CLR;
186 putreg32(regval, reg_base + I2C_INT_STS_OFFSET);
187 }
188
bflb_i2c_isenable(struct bflb_device_s * dev)189 static inline bool bflb_i2c_isenable(struct bflb_device_s *dev)
190 {
191 uint32_t regval;
192 uint32_t reg_base;
193
194 reg_base = dev->reg_base;
195
196 regval = getreg32(reg_base + I2C_CONFIG_OFFSET);
197 if (regval & I2C_CR_I2C_M_EN) {
198 return true;
199 }
200
201 return false;
202 }
203
bflb_i2c_write_bytes(struct bflb_device_s * dev,uint8_t * data,uint32_t len)204 static int bflb_i2c_write_bytes(struct bflb_device_s *dev, uint8_t *data, uint32_t len)
205 {
206 uint32_t reg_base;
207 uint32_t temp = 0;
208 uint8_t *tmp_buf;
209 // uint64_t start_time;
210
211 reg_base = dev->reg_base;
212 tmp_buf = data;
213 while (len >= 4) {
214 for (uint8_t i = 0; i < 4; i++) {
215 temp += (tmp_buf[i] << ((i % 4) * 8));
216 }
217 tmp_buf += 4;
218 len -= 4;
219 // start_time = bflb_mtimer_get_time_ms();
220 // while ((getreg32(reg_base + I2C_FIFO_CONFIG_1_OFFSET) & I2C_TX_FIFO_CNT_MASK) == 0) {
221 // if ((bflb_mtimer_get_time_ms() - start_time) > 100) {
222 // return -ETIMEDOUT;
223 // }
224 // }
225 putreg32(temp, reg_base + I2C_FIFO_WDATA_OFFSET);
226 if (!bflb_i2c_isenable(dev)) {
227 bflb_i2c_enable(dev);
228 }
229 temp = 0;
230 }
231
232 if (len > 0) {
233 for (uint8_t i = 0; i < len; i++) {
234 temp += (tmp_buf[i] << ((i % 4) * 8));
235 }
236 // start_time = bflb_mtimer_get_time_ms();
237 // while ((getreg32(reg_base + I2C_FIFO_CONFIG_1_OFFSET) & I2C_TX_FIFO_CNT_MASK) == 0) {
238 // if ((bflb_mtimer_get_time_ms() - start_time) > 100) {
239 // return -ETIMEDOUT;
240 // }
241 // }
242 putreg32(temp, reg_base + I2C_FIFO_WDATA_OFFSET);
243 if (!bflb_i2c_isenable(dev)) {
244 bflb_i2c_enable(dev);
245 }
246 }
247
248 // start_time = bflb_mtimer_get_time_ms();
249 // while (bflb_i2c_isbusy(dev) || !bflb_i2c_isend(dev) || bflb_i2c_isnak(dev)) {
250 // if ((bflb_mtimer_get_time_ms() - start_time) > 100) {
251 // return -ETIMEDOUT;
252 // }
253 // }
254 bflb_i2c_disable(dev);
255
256 return 0;
257 }
258
bflb_i2c_read_bytes(struct bflb_device_s * dev,uint8_t * data,uint32_t len)259 static int bflb_i2c_read_bytes(struct bflb_device_s *dev, uint8_t *data, uint32_t len)
260 {
261 uint32_t reg_base;
262 uint32_t temp = 0;
263 uint8_t *tmp_buf;
264 // uint64_t start_time;
265
266 reg_base = dev->reg_base;
267 tmp_buf = data;
268
269 bflb_i2c_enable(dev);
270
271 while (len >= 4) {
272 // start_time = bflb_mtimer_get_time_ms();
273 // while ((getreg32(reg_base + I2C_FIFO_CONFIG_1_OFFSET) & I2C_RX_FIFO_CNT_MASK) == 0) {
274 // if ((bflb_mtimer_get_time_ms() - start_time) > 100) {
275 // return -ETIMEDOUT;
276 // }
277 // }
278 temp = getreg32(reg_base + I2C_FIFO_RDATA_OFFSET);
279 PUT_UINT32_LE(tmp_buf, temp);
280 tmp_buf += 4;
281 len -= 4;
282 }
283
284 if (len > 0) {
285 // start_time = bflb_mtimer_get_time_ms();
286 // while ((getreg32(reg_base + I2C_FIFO_CONFIG_1_OFFSET) & I2C_RX_FIFO_CNT_MASK) == 0) {
287 // if ((bflb_mtimer_get_time_ms() - start_time) > 100) {
288 // return -ETIMEDOUT;
289 // }
290 // }
291 temp = getreg32(reg_base + I2C_FIFO_RDATA_OFFSET);
292
293 for (uint8_t i = 0; i < len; i++) {
294 tmp_buf[i] = (temp >> (i * 8)) & 0xff;
295 }
296 }
297
298 // start_time = bflb_mtimer_get_time_ms();
299 // while (bflb_i2c_isbusy(dev) || !bflb_i2c_isend(dev)) {
300 // if ((bflb_mtimer_get_time_ms() - start_time) > 100) {
301 // return -ETIMEDOUT;
302 // }
303 // }
304 bflb_i2c_disable(dev);
305
306 return 0;
307 }
308
bflb_i2c_init(struct bflb_device_s * dev,uint32_t frequency)309 void bflb_i2c_init(struct bflb_device_s *dev, uint32_t frequency)
310 {
311 uint32_t regval;
312 uint32_t reg_base;
313
314 reg_base = dev->reg_base;
315
316 bflb_i2c_disable(dev);
317
318 regval = getreg32(reg_base + I2C_INT_STS_OFFSET);
319
320 regval |= (I2C_CR_I2C_END_MASK |
321 I2C_CR_I2C_TXF_MASK |
322 I2C_CR_I2C_RXF_MASK |
323 I2C_CR_I2C_NAK_MASK |
324 I2C_CR_I2C_ARB_MASK |
325 I2C_CR_I2C_FER_MASK);
326
327 putreg32(regval, reg_base + I2C_INT_STS_OFFSET);
328
329 bflb_i2c_set_frequence(dev, frequency);
330 }
331
bflb_i2c_deinit(struct bflb_device_s * dev)332 void bflb_i2c_deinit(struct bflb_device_s *dev)
333 {
334 uint32_t regval;
335 uint32_t reg_base;
336
337 reg_base = dev->reg_base;
338
339 bflb_i2c_disable(dev);
340
341 regval = getreg32(reg_base + I2C_INT_STS_OFFSET);
342
343 regval |= (I2C_CR_I2C_END_MASK |
344 I2C_CR_I2C_TXF_MASK |
345 I2C_CR_I2C_RXF_MASK |
346 I2C_CR_I2C_NAK_MASK |
347 I2C_CR_I2C_ARB_MASK |
348 I2C_CR_I2C_FER_MASK);
349
350 putreg32(regval, reg_base + I2C_INT_STS_OFFSET);
351 }
352
bflb_i2c_link_txdma(struct bflb_device_s * dev,bool enable)353 void bflb_i2c_link_txdma(struct bflb_device_s *dev, bool enable)
354 {
355 uint32_t reg_base;
356 uint32_t regval;
357
358 reg_base = dev->reg_base;
359 regval = getreg32(reg_base + I2C_FIFO_CONFIG_0_OFFSET);
360 if (enable) {
361 regval |= I2C_DMA_TX_EN;
362 } else {
363 regval &= ~I2C_DMA_TX_EN;
364 }
365 putreg32(regval, reg_base + I2C_FIFO_CONFIG_0_OFFSET);
366 }
367
bflb_i2c_link_rxdma(struct bflb_device_s * dev,bool enable)368 void bflb_i2c_link_rxdma(struct bflb_device_s *dev, bool enable)
369 {
370 uint32_t reg_base;
371 uint32_t regval;
372
373 reg_base = dev->reg_base;
374 regval = getreg32(reg_base + I2C_FIFO_CONFIG_0_OFFSET);
375 if (enable) {
376 regval |= I2C_DMA_RX_EN;
377 } else {
378 regval &= ~I2C_DMA_RX_EN;
379 }
380 putreg32(regval, reg_base + I2C_FIFO_CONFIG_0_OFFSET);
381 }
382
bflb_i2c_transfer(struct bflb_device_s * dev,struct bflb_i2c_msg_s * msgs,int count)383 int bflb_i2c_transfer(struct bflb_device_s *dev, struct bflb_i2c_msg_s *msgs, int count)
384 {
385 uint16_t subaddr = 0;
386 uint16_t subaddr_size = 0;
387 bool is_addr_10bit = false;
388 int ret = 0;
389
390 bflb_i2c_disable(dev);
391
392 for (uint16_t i = 0; i < count; i++) {
393 if (msgs[i].flags & I2C_M_TEN) {
394 is_addr_10bit = true;
395 } else {
396 is_addr_10bit = false;
397 }
398 if (msgs[i].flags & I2C_M_NOSTOP) {
399 subaddr = 0;
400 for (uint8_t j = 0; j < msgs[i].length; j++) {
401 subaddr += msgs[i].buffer[j] << (j * 8);
402 }
403 subaddr_size = msgs[i].length;
404 bflb_i2c_addr_config(dev, msgs[i].addr, subaddr, subaddr_size, is_addr_10bit);
405 i++;
406 } else {
407 subaddr = 0;
408 subaddr_size = 0;
409 bflb_i2c_addr_config(dev, msgs[i].addr, subaddr, subaddr_size, is_addr_10bit);
410 }
411
412 if (msgs[i].length > 256) {
413 return -EINVAL;
414 }
415 bflb_i2c_set_datalen(dev, msgs[i].length);
416 if (msgs[i].flags & I2C_M_READ) {
417 bflb_i2c_set_dir(dev, 1);
418 if ((msgs[i].flags & I2C_M_DMA) == 0) {
419 ret = bflb_i2c_read_bytes(dev, msgs[i].buffer, msgs[i].length);
420 if (ret < 0) {
421 return ret;
422 }
423 } else {
424 bflb_i2c_enable(dev);
425 }
426 } else {
427 bflb_i2c_set_dir(dev, 0);
428 if ((msgs[i].flags & I2C_M_DMA) == 0) {
429 ret = bflb_i2c_write_bytes(dev, msgs[i].buffer, msgs[i].length);
430 if (ret < 0) {
431 return ret;
432 }
433 } else {
434 bflb_i2c_enable(dev);
435 }
436 }
437 }
438
439 return 0;
440 }
441
bflb_i2c_int_mask(struct bflb_device_s * dev,uint32_t int_type,bool mask)442 void bflb_i2c_int_mask(struct bflb_device_s *dev, uint32_t int_type, bool mask)
443 {
444 uint32_t reg_base;
445 uint32_t regval;
446
447 reg_base = dev->reg_base;
448 regval = getreg32(reg_base + I2C_INT_STS_OFFSET);
449 regval &= ~((int_type & 0xff) << 8);
450 if (mask) {
451 regval |= (int_type & 0xff) << 8;
452 }
453 putreg32(regval, reg_base + I2C_INT_STS_OFFSET);
454 }
455
bflb_i2c_int_clear(struct bflb_device_s * dev,uint32_t int_clear)456 void bflb_i2c_int_clear(struct bflb_device_s *dev, uint32_t int_clear)
457 {
458 uint32_t reg_base;
459 uint32_t regval;
460
461 reg_base = dev->reg_base;
462 regval = getreg32(reg_base + I2C_INT_STS_OFFSET);
463 regval |= (int_clear & 0xff) << 16;
464 putreg32(regval, reg_base + I2C_INT_STS_OFFSET);
465 }
466
bflb_i2c_get_intstatus(struct bflb_device_s * dev)467 uint32_t bflb_i2c_get_intstatus(struct bflb_device_s *dev)
468 {
469 uint32_t reg_base;
470
471 reg_base = dev->reg_base;
472 return (getreg32(reg_base + I2C_INT_STS_OFFSET) & 0xff);
473 }
474
bflb_i2c_feature_control(struct bflb_device_s * dev,int cmd,size_t arg)475 int bflb_i2c_feature_control(struct bflb_device_s *dev, int cmd, size_t arg)
476 {
477 int ret = 0;
478 switch (cmd) {
479 default:
480 ret = -EPERM;
481 break;
482 }
483 return ret;
484 }
485