Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bdk/soc/i2c.c
3694 views
1
/*
2
* Copyright (c) 2018 naehrwert
3
* Copyright (c) 2018-2026 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_PACKET_TRANSFER_STATUS (0x58 / 4)
53
#define PKT_TRANSFER_COMPLETE BIT(24)
54
55
#define I2C_FIFO_CONTROL (0x5C / 4)
56
#define RX_FIFO_FLUSH BIT(0)
57
#define TX_FIFO_FLUSH BIT(1)
58
59
#define I2C_FIFO_STATUS (0x60 / 4)
60
#define RX_FIFO_FULL_CNT (0xF << 0)
61
#define TX_FIFO_EMPTY_CNT (0xF << 4)
62
63
#define I2C_INT_EN (0x64 / 4)
64
#define I2C_INT_STATUS (0x68 / 4)
65
#define I2C_INT_SOURCE (0x70 / 4)
66
#define RX_FIFO_DATA_REQ BIT(0)
67
#define TX_FIFO_DATA_REQ BIT(1)
68
#define ARB_LOST BIT(2)
69
#define NO_ACK BIT(3)
70
#define RX_FIFO_UNDER BIT(4)
71
#define TX_FIFO_OVER BIT(5)
72
#define ALL_PACKETS_COMPLETE BIT(6)
73
#define PACKET_COMPLETE BIT(7)
74
#define BUS_CLEAR_DONE BIT(11)
75
76
#define I2C_CLK_DIVISOR (0x6C / 4)
77
78
#define I2C_BUS_CLEAR_CONFIG (0x84 / 4)
79
#define BC_ENABLE BIT(0)
80
#define BC_TERMINATE BIT(1)
81
82
#define I2C_BUS_CLEAR_STATUS (0x88 / 4)
83
84
#define I2C_CONFIG_LOAD (0x8C / 4)
85
#define MSTR_CONFIG_LOAD BIT(0)
86
#define TIMEOUT_CONFIG_LOAD BIT(2)
87
88
/* I2C_1, 2, 3, 4, 5 and 6. */
89
static const u16 _i2c_base_offsets[6] = { 0x0, 0x400, 0x500, 0x700, 0x1000, 0x1100 };
90
91
static void _i2c_load_cfg_wait(vu32 *base)
92
{
93
base[I2C_CONFIG_LOAD] = BIT(5) | TIMEOUT_CONFIG_LOAD | MSTR_CONFIG_LOAD;
94
for (u32 i = 0; i < 20; i++)
95
{
96
if (!(base[I2C_CONFIG_LOAD] & MSTR_CONFIG_LOAD))
97
break;
98
usleep(1);
99
}
100
}
101
102
static int _i2c_send_normal(u32 i2c_idx, u32 dev_addr, const u8 *buf, u32 size)
103
{
104
if (size > 8)
105
return 1;
106
107
u32 tmp = 0;
108
109
vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);
110
111
// Set device address and send mode.
112
base[I2C_CMD_ADDR0] = dev_addr << 1 | ADDR0_WRITE;
113
114
if (size > 4)
115
{
116
memcpy(&tmp, buf, 4);
117
base[I2C_CMD_DATA1] = tmp; //Set value.
118
tmp = 0;
119
memcpy(&tmp, buf + 4, size - 4);
120
base[I2C_CMD_DATA2] = tmp;
121
}
122
else
123
{
124
memcpy(&tmp, buf, size);
125
base[I2C_CMD_DATA1] = tmp; //Set value.
126
}
127
128
// Set size and send mode.
129
base[I2C_CNFG] = ((size - 1) << 1) | DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_WRITE;
130
131
// Load configuration.
132
_i2c_load_cfg_wait(base);
133
134
// Initiate transaction on normal mode.
135
base[I2C_CNFG] = (base[I2C_CNFG] & ~NORMAL_MODE_GO) | NORMAL_MODE_GO;
136
137
u32 timeout = get_tmr_ms() + 100; // Actual for max 8 bytes at 100KHz is 0.74ms.
138
while (base[I2C_STATUS] & I2C_STATUS_BUSY)
139
{
140
if (get_tmr_ms() > timeout)
141
return 1;
142
}
143
144
if (base[I2C_STATUS] & I2C_STATUS_NOACK)
145
return 1;
146
147
return 0;
148
}
149
150
static int _i2c_recv_normal(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr)
151
{
152
if (size > 8)
153
return 1;
154
155
vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);
156
157
// Set device address and recv mode.
158
base[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_READ;
159
160
// Set size and recv mode.
161
base[I2C_CNFG] = ((size - 1) << 1) | DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_READ;
162
163
// Load configuration.
164
_i2c_load_cfg_wait(base);
165
166
// Initiate transaction on normal mode.
167
base[I2C_CNFG] = (base[I2C_CNFG] & ~NORMAL_MODE_GO) | NORMAL_MODE_GO;
168
169
u32 timeout = get_tmr_ms() + 100; // Actual for max 8 bytes at 100KHz is 0.74ms.
170
while (base[I2C_STATUS] & I2C_STATUS_BUSY)
171
{
172
if (get_tmr_ms() > timeout)
173
return 1;
174
}
175
176
if (base[I2C_STATUS] & I2C_STATUS_NOACK)
177
return 1;
178
179
u32 tmp = base[I2C_CMD_DATA1]; // Get LS value.
180
if (size > 4)
181
{
182
memcpy(buf, &tmp, 4);
183
tmp = base[I2C_CMD_DATA2]; // Get MS value.
184
memcpy(buf + 4, &tmp, size - 4);
185
}
186
else
187
memcpy(buf, &tmp, size);
188
189
return 0;
190
}
191
192
static int _i2c_send_packet(u32 i2c_idx, const u8 *buf, u32 size, u32 dev_addr)
193
{
194
if (size > 32)
195
return 1;
196
197
int res = 0;
198
199
vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);
200
201
// Set device address and send mode.
202
base[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_WRITE;
203
204
// Set recv mode.
205
base[I2C_CNFG] = DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_WRITE;
206
207
// Set and flush FIFO.
208
base[I2C_FIFO_CONTROL] = RX_FIFO_FLUSH | TX_FIFO_FLUSH;
209
210
// Load configuration.
211
_i2c_load_cfg_wait(base);
212
213
// Initiate transaction on packet mode.
214
base[I2C_CNFG] = (base[I2C_CNFG] & ~NORMAL_MODE_GO) | PACKET_MODE_GO;
215
216
// Send header with request.
217
base[I2C_TX_FIFO] = I2C_PACKET_PROT_I2C;
218
base[I2C_TX_FIFO] = size - 1;
219
base[I2C_TX_FIFO] = I2C_HEADER_IE_ENABLE | I2C_HEADER_CONT_XFER | (dev_addr << 1);
220
221
// Send data.
222
u32 rem = size;
223
while (rem)
224
{
225
u32 len = MIN(rem, sizeof(u32));
226
u32 word = 0;
227
memcpy(&word, buf, len);
228
base[I2C_TX_FIFO] = word;
229
buf += len;
230
rem -= len;
231
}
232
233
u32 timeout = get_tmr_ms() + 200;
234
while (((base[I2C_PACKET_TRANSFER_STATUS] >> 4) & 0xFFF) != (size - 1))
235
{
236
if (get_tmr_ms() > timeout)
237
{
238
res = 1;
239
break;
240
}
241
}
242
243
// Check if no reply.
244
if (base[I2C_STATUS] & I2C_STATUS_NOACK)
245
res = 1;
246
247
// Wait for STOP and disable packet mode.
248
usleep(20);
249
base[I2C_CNFG] &= ~(PACKET_MODE_GO | NORMAL_MODE_GO);
250
251
return res;
252
}
253
254
int i2c_xfer_packet(u32 i2c_idx, u32 dev_addr, const u8 *tx_buf, u32 tx_size, u8 *rx_buf, u32 rx_size)
255
{
256
// Max 32 bytes TX/RX fifo.
257
if (tx_size > 20 || rx_size > 32) // Header included.
258
return 1;
259
260
int res = 0;
261
262
vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);
263
264
// Set device address and recv mode.
265
base[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_READ;
266
267
// Set recv mode.
268
base[I2C_CNFG] = DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_READ;
269
270
// Set and flush FIFO.
271
base[I2C_FIFO_CONTROL] = RX_FIFO_FLUSH | TX_FIFO_FLUSH;
272
273
// Load configuration.
274
_i2c_load_cfg_wait(base);
275
276
// Initiate transaction on packet mode.
277
base[I2C_CNFG] = (base[I2C_CNFG] & ~NORMAL_MODE_GO) | PACKET_MODE_GO;
278
279
// Send header with send request.
280
base[I2C_TX_FIFO] = I2C_PACKET_PROT_I2C;
281
base[I2C_TX_FIFO] = tx_size - 1;
282
base[I2C_TX_FIFO] = I2C_HEADER_REP_START | (dev_addr << 1);
283
284
// Send data.
285
u32 tx_rem = tx_size;
286
while (tx_rem)
287
{
288
u32 len = MIN(tx_rem, sizeof(u32));
289
u32 word = 0;
290
memcpy(&word, tx_buf, len);
291
base[I2C_TX_FIFO] = word;
292
tx_buf += len;
293
tx_rem -= len;
294
}
295
296
u32 timeout = get_tmr_ms() + 200;
297
while (((base[I2C_PACKET_TRANSFER_STATUS] >> 4) & 0xFFF) != (tx_size - 1))
298
{
299
if (get_tmr_ms() > timeout)
300
{
301
res = 1;
302
goto out;
303
}
304
}
305
306
// Send header with receive request
307
base[I2C_TX_FIFO] = I2C_PACKET_PROT_I2C;
308
base[I2C_TX_FIFO] = rx_size - 1;
309
base[I2C_TX_FIFO] = I2C_HEADER_READ | (dev_addr << 1);
310
311
// Receive data.
312
timeout = get_tmr_ms() + 200;
313
while (rx_size)
314
{
315
if (base[I2C_FIFO_STATUS] & RX_FIFO_FULL_CNT)
316
{
317
u32 len = MIN(rx_size, sizeof(u32));
318
u32 word = base[I2C_RX_FIFO];
319
memcpy(rx_buf, &word, len);
320
rx_buf += len;
321
rx_size -= len;
322
}
323
324
if (get_tmr_ms() > timeout)
325
{
326
res = 1;
327
break;
328
}
329
}
330
331
out:
332
// Check if no reply.
333
if (base[I2C_STATUS] & I2C_STATUS_NOACK)
334
res = 1;
335
336
// Wait for STOP and disable packet mode.
337
usleep(20);
338
base[I2C_CNFG] &= ~(PACKET_MODE_GO | NORMAL_MODE_GO);
339
340
return res;
341
}
342
343
void i2c_init(u32 i2c_idx)
344
{
345
vu32 *base = (vu32 *)(I2C_BASE + (u32)_i2c_base_offsets[i2c_idx]);
346
347
base[I2C_CLK_DIVISOR] = (5 << 16) | 1; // SF mode Div: 6, HS mode div: 2.
348
base[I2C_BUS_CLEAR_CONFIG] = (9 << 16) | BC_TERMINATE | BC_ENABLE;
349
350
// Load configuration.
351
_i2c_load_cfg_wait(base);
352
353
for (u32 i = 0; i < 10; i++)
354
{
355
if (base[I2C_INT_STATUS] & BUS_CLEAR_DONE)
356
break;
357
usleep(25);
358
}
359
360
(vu32)base[I2C_BUS_CLEAR_STATUS];
361
base[I2C_INT_STATUS] = base[I2C_INT_STATUS];
362
}
363
364
int i2c_send_buf_big(u32 i2c_idx, u32 dev_addr, const u8 *buf, u32 size)
365
{
366
return _i2c_send_packet(i2c_idx, buf, size, dev_addr);
367
}
368
369
int i2c_recv_buf_big(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg)
370
{
371
return i2c_xfer_packet(i2c_idx, dev_addr, (u8 *)&reg, 1, buf, size);
372
}
373
374
int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, const u8 *buf, u32 size)
375
{
376
if (size > 7)
377
return 1;
378
379
u8 tmp[8];
380
tmp[0] = reg;
381
memcpy(tmp + 1, buf, size);
382
383
return _i2c_send_normal(i2c_idx, dev_addr, tmp, size + 1);
384
}
385
386
int i2c_recv_buf_small(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg)
387
{
388
int res = _i2c_send_normal(i2c_idx, dev_addr, (u8 *)&reg, 1);
389
if (!res)
390
res = _i2c_recv_normal(i2c_idx, buf, size, dev_addr);
391
return res;
392
}
393
394
int i2c_send_byte(u32 i2c_idx, u32 dev_addr, u32 reg, u8 val)
395
{
396
return i2c_send_buf_small(i2c_idx, dev_addr, reg, &val, 1);
397
}
398
399
u8 i2c_recv_byte(u32 i2c_idx, u32 dev_addr, u32 reg)
400
{
401
u8 tmp = 0;
402
i2c_recv_buf_small(&tmp, 1, i2c_idx, dev_addr, reg);
403
return tmp;
404
}
405
406
407