Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bdk/soc/i2c.c
1476 views
1
/*
2
* Copyright (c) 2018 naehrwert
3
* Copyright (c) 2018-2022 CTCaer
4
*
5
* This program is free software; you can redistribute it and/or modify it
6
* under the terms and conditions of the GNU General Public License,
7
* version 2, as published by the Free Software Foundation.
8
*
9
* This program is distributed in the hope it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12
* more details.
13
*
14
* You should have received a copy of the GNU General Public License
15
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
*/
17
18
#include <string.h>
19
20
#include <soc/i2c.h>
21
#include <soc/t210.h>
22
#include <soc/timer.h>
23
24
#define I2C_PACKET_PROT_I2C BIT(4)
25
#define I2C_HEADER_CONT_XFER BIT(15)
26
#define I2C_HEADER_REP_START BIT(16)
27
#define I2C_HEADER_IE_ENABLE BIT(17)
28
#define I2C_HEADER_READ BIT(19)
29
30
#define I2C_CNFG (0x00 / 4)
31
#define CMD1_WRITE (0 << 6)
32
#define CMD1_READ BIT(6)
33
#define NORMAL_MODE_GO BIT(9)
34
#define PACKET_MODE_GO BIT(10)
35
#define NEW_MASTER_FSM BIT(11)
36
#define DEBOUNCE_CNT_4T (2 << 12)
37
38
#define I2C_CMD_ADDR0 (0x04 / 4)
39
#define ADDR0_WRITE 0
40
#define ADDR0_READ 1
41
42
#define I2C_CMD_DATA1 (0x0C / 4)
43
#define I2C_CMD_DATA2 (0x10 / 4)
44
45
#define I2C_STATUS (0x1C / 4)
46
#define I2C_STATUS_NOACK (0xF << 0)
47
#define I2C_STATUS_BUSY BIT(8)
48
49
#define I2C_TX_FIFO (0x50 / 4)
50
#define I2C_RX_FIFO (0x54 / 4)
51
52
#define I2C_FIFO_CONTROL (0x5C / 4)
53
#define RX_FIFO_FLUSH BIT(0)
54
#define TX_FIFO_FLUSH BIT(1)
55
56
#define I2C_FIFO_STATUS (0x60 / 4)
57
#define RX_FIFO_FULL_CNT (0xF << 0)
58
#define TX_FIFO_EMPTY_CNT (0xF << 4)
59
60
#define I2C_INT_EN (0x64 / 4)
61
#define I2C_INT_STATUS (0x68 / 4)
62
#define I2C_INT_SOURCE (0x70 / 4)
63
#define RX_FIFO_DATA_REQ BIT(0)
64
#define TX_FIFO_DATA_REQ BIT(1)
65
#define ARB_LOST BIT(2)
66
#define NO_ACK BIT(3)
67
#define RX_FIFO_UNDER BIT(4)
68
#define TX_FIFO_OVER BIT(5)
69
#define ALL_PACKETS_COMPLETE BIT(6)
70
#define PACKET_COMPLETE BIT(7)
71
#define BUS_CLEAR_DONE BIT(11)
72
73
#define I2C_CLK_DIVISOR (0x6C / 4)
74
75
#define I2C_BUS_CLEAR_CONFIG (0x84 / 4)
76
#define BC_ENABLE BIT(0)
77
#define BC_TERMINATE BIT(1)
78
79
#define I2C_BUS_CLEAR_STATUS (0x88 / 4)
80
81
#define I2C_CONFIG_LOAD (0x8C / 4)
82
#define MSTR_CONFIG_LOAD BIT(0)
83
#define TIMEOUT_CONFIG_LOAD BIT(2)
84
85
/* I2C_1, 2, 3, 4, 5 and 6. */
86
static const u16 _i2c_base_offsets[6] = { 0x0, 0x400, 0x500, 0x700, 0x1000, 0x1100 };
87
88
static void _i2c_load_cfg_wait(vu32 *base)
89
{
90
base[I2C_CONFIG_LOAD] = BIT(5) | TIMEOUT_CONFIG_LOAD | MSTR_CONFIG_LOAD;
91
for (u32 i = 0; i < 20; i++)
92
{
93
if (!(base[I2C_CONFIG_LOAD] & MSTR_CONFIG_LOAD))
94
break;
95
usleep(1);
96
}
97
}
98
99
static int _i2c_send_single(u32 i2c_idx, u32 dev_addr, const u8 *buf, u32 size)
100
{
101
if (size > 8)
102
return 0;
103
104
u32 tmp = 0;
105
106
vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);
107
108
// Set device address and send mode.
109
base[I2C_CMD_ADDR0] = dev_addr << 1 | ADDR0_WRITE;
110
111
if (size > 4)
112
{
113
memcpy(&tmp, buf, 4);
114
base[I2C_CMD_DATA1] = tmp; //Set value.
115
tmp = 0;
116
memcpy(&tmp, buf + 4, size - 4);
117
base[I2C_CMD_DATA2] = tmp;
118
}
119
else
120
{
121
memcpy(&tmp, buf, size);
122
base[I2C_CMD_DATA1] = tmp; //Set value.
123
}
124
125
// Set size and send mode.
126
base[I2C_CNFG] = ((size - 1) << 1) | DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_WRITE;
127
128
// Load configuration.
129
_i2c_load_cfg_wait(base);
130
131
// Initiate transaction on normal mode.
132
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | NORMAL_MODE_GO;
133
134
u32 timeout = get_tmr_us() + 200000; // Actual for max 8 bytes at 100KHz is 0.74ms.
135
while (base[I2C_STATUS] & I2C_STATUS_BUSY)
136
{
137
if (get_tmr_us() > timeout)
138
return 0;
139
}
140
141
if (base[I2C_STATUS] & I2C_STATUS_NOACK)
142
return 0;
143
144
return 1;
145
}
146
147
static int _i2c_recv_single(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr)
148
{
149
if (size > 8)
150
return 0;
151
152
vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);
153
154
// Set device address and recv mode.
155
base[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_READ;
156
157
// Set size and recv mode.
158
base[I2C_CNFG] = ((size - 1) << 1) | DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_READ;
159
160
// Load configuration.
161
_i2c_load_cfg_wait(base);
162
163
// Initiate transaction on normal mode.
164
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | NORMAL_MODE_GO;
165
166
u32 timeout = get_tmr_us() + 200000; // Actual for max 8 bytes at 100KHz is 0.74ms.
167
while (base[I2C_STATUS] & I2C_STATUS_BUSY)
168
{
169
if (get_tmr_us() > timeout)
170
return 0;
171
}
172
173
if (base[I2C_STATUS] & I2C_STATUS_NOACK)
174
return 0;
175
176
u32 tmp = base[I2C_CMD_DATA1]; // Get LS value.
177
if (size > 4)
178
{
179
memcpy(buf, &tmp, 4);
180
tmp = base[I2C_CMD_DATA2]; // Get MS value.
181
memcpy(buf + 4, &tmp, size - 4);
182
}
183
else
184
memcpy(buf, &tmp, size);
185
186
return 1;
187
}
188
189
static int _i2c_send_pkt(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr)
190
{
191
if (size > 32)
192
return 0;
193
194
int res = 0;
195
196
vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);
197
198
// Enable interrupts.
199
base[I2C_INT_EN] = ALL_PACKETS_COMPLETE | PACKET_COMPLETE | NO_ACK |
200
ARB_LOST | TX_FIFO_OVER | RX_FIFO_UNDER | TX_FIFO_DATA_REQ;
201
base[I2C_INT_STATUS] = base[I2C_INT_STATUS];
202
203
// Set device address and send mode.
204
base[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_WRITE;
205
206
// Set recv mode.
207
base[I2C_CNFG] = DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_WRITE;
208
209
// Set and flush FIFO.
210
base[I2C_FIFO_CONTROL] = RX_FIFO_FLUSH | TX_FIFO_FLUSH;
211
212
// Load configuration.
213
_i2c_load_cfg_wait(base);
214
215
// Initiate transaction on packet mode.
216
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | PACKET_MODE_GO;
217
218
u32 hdr[3];
219
hdr[0] = I2C_PACKET_PROT_I2C;
220
hdr[1] = size - 1;
221
hdr[2] = I2C_HEADER_IE_ENABLE | I2C_HEADER_CONT_XFER | (dev_addr << 1);
222
223
// Send header with request.
224
base[I2C_TX_FIFO] = hdr[0];
225
base[I2C_TX_FIFO] = hdr[1];
226
base[I2C_TX_FIFO] = hdr[2];
227
228
u32 timeout = get_tmr_ms() + 400;
229
while (size)
230
{
231
if (base[I2C_FIFO_STATUS] & TX_FIFO_EMPTY_CNT)
232
{
233
u32 tmp = 0;
234
u32 snd_size = MIN(size, 4);
235
memcpy(&tmp, buf, snd_size);
236
base[I2C_TX_FIFO] = tmp;
237
buf += snd_size;
238
size -= snd_size;
239
}
240
241
if (get_tmr_ms() > timeout)
242
{
243
res = 1;
244
break;
245
}
246
}
247
248
if (base[I2C_STATUS] & I2C_STATUS_NOACK || base[I2C_INT_STATUS] & NO_ACK)
249
res = 1;
250
251
// Disable packet mode.
252
usleep(20);
253
base[I2C_CNFG] &= 0xFFFFF9FF;
254
255
// Disable interrupts.
256
base[I2C_INT_EN] = 0;
257
258
return res;
259
}
260
261
static int _i2c_recv_pkt(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr, u32 reg)
262
{
263
if (size > 32)
264
return 0;
265
266
int res = 0;
267
268
vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);
269
270
// Enable interrupts.
271
base[I2C_INT_EN] = ALL_PACKETS_COMPLETE | PACKET_COMPLETE | NO_ACK |
272
ARB_LOST | TX_FIFO_OVER | RX_FIFO_UNDER | RX_FIFO_DATA_REQ;
273
base[I2C_INT_STATUS] = base[I2C_INT_STATUS];
274
275
// Set device address and recv mode.
276
base[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_READ;
277
278
// Set recv mode.
279
base[I2C_CNFG] = DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_READ;
280
281
// Set and flush FIFO.
282
base[I2C_FIFO_CONTROL] = RX_FIFO_FLUSH | TX_FIFO_FLUSH;
283
284
// Load configuration.
285
_i2c_load_cfg_wait(base);
286
287
// Initiate transaction on packet mode.
288
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | PACKET_MODE_GO;
289
290
// Send reg request.
291
u32 hdr[3];
292
hdr[0] = I2C_PACKET_PROT_I2C;
293
hdr[1] = 1 - 1;
294
hdr[2] = I2C_HEADER_REP_START | (dev_addr << 1);
295
296
// Send header with reg request.
297
base[I2C_TX_FIFO] = hdr[0];
298
base[I2C_TX_FIFO] = hdr[1];
299
base[I2C_TX_FIFO] = hdr[2];
300
base[I2C_TX_FIFO] = reg;
301
302
u32 timeout = get_tmr_ms() + 400;
303
while (!(base[I2C_FIFO_STATUS] & TX_FIFO_EMPTY_CNT))
304
if (get_tmr_ms() > timeout)
305
break;
306
307
// Send read request.
308
hdr[1] = size - 1;
309
hdr[2] = I2C_HEADER_READ | (dev_addr << 1);
310
311
// Send header with read request.
312
base[I2C_TX_FIFO] = hdr[0];
313
base[I2C_TX_FIFO] = hdr[1];
314
base[I2C_TX_FIFO] = hdr[2];
315
316
timeout = get_tmr_ms() + 400;
317
while (size)
318
{
319
if (base[I2C_FIFO_STATUS] & RX_FIFO_FULL_CNT)
320
{
321
u32 rcv_size = MIN(size, 4);
322
u32 tmp = base[I2C_RX_FIFO];
323
memcpy(buf, &tmp, rcv_size);
324
buf += rcv_size;
325
size -= rcv_size;
326
}
327
328
if (get_tmr_ms() > timeout)
329
{
330
res = 1;
331
break;
332
}
333
}
334
335
if (base[I2C_STATUS] & I2C_STATUS_NOACK || base[I2C_INT_STATUS] & NO_ACK)
336
res = 1;
337
338
// Disable packet mode.
339
usleep(20);
340
base[I2C_CNFG] &= 0xFFFFF9FF;
341
342
// Disable interrupts.
343
base[I2C_INT_EN] = 0;
344
345
return res;
346
}
347
348
void i2c_init(u32 i2c_idx)
349
{
350
vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);
351
352
base[I2C_CLK_DIVISOR] = (5 << 16) | 1; // SF mode Div: 6, HS mode div: 2.
353
base[I2C_BUS_CLEAR_CONFIG] = (9 << 16) | BC_TERMINATE | BC_ENABLE;
354
355
// Load configuration.
356
_i2c_load_cfg_wait(base);
357
358
for (u32 i = 0; i < 10; i++)
359
{
360
if (base[I2C_INT_STATUS] & BUS_CLEAR_DONE)
361
break;
362
usleep(25);
363
}
364
365
(vu32)base[I2C_BUS_CLEAR_STATUS];
366
base[I2C_INT_STATUS] = base[I2C_INT_STATUS];
367
}
368
369
int i2c_recv_buf(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr)
370
{
371
return _i2c_recv_single(i2c_idx, buf, size, dev_addr);
372
}
373
374
int i2c_send_buf_big(u32 i2c_idx, u32 dev_addr, u8 *buf, u32 size)
375
{
376
if (size > 32)
377
return 0;
378
379
return _i2c_send_pkt(i2c_idx, buf, size, dev_addr);
380
}
381
382
int i2c_recv_buf_big(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg)
383
{
384
return _i2c_recv_pkt(i2c_idx, buf, size, dev_addr, reg);
385
}
386
387
int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, const u8 *buf, u32 size)
388
{
389
u8 tmp[8];
390
391
if (size > 7)
392
return 0;
393
394
tmp[0] = reg;
395
memcpy(tmp + 1, buf, size);
396
397
return _i2c_send_single(i2c_idx, dev_addr, tmp, size + 1);
398
}
399
400
int i2c_recv_buf_small(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg)
401
{
402
int res = _i2c_send_single(i2c_idx, dev_addr, (u8 *)&reg, 1);
403
if (res)
404
res = _i2c_recv_single(i2c_idx, buf, size, dev_addr);
405
return res;
406
}
407
408
int i2c_send_byte(u32 i2c_idx, u32 dev_addr, u32 reg, u8 val)
409
{
410
return i2c_send_buf_small(i2c_idx, dev_addr, reg, &val, 1);
411
}
412
413
u8 i2c_recv_byte(u32 i2c_idx, u32 dev_addr, u32 reg)
414
{
415
u8 tmp = 0;
416
i2c_recv_buf_small(&tmp, 1, i2c_idx, dev_addr, reg);
417
return tmp;
418
}
419
420
421