• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "hpm_i2c_drv.h"
9 
10 #ifndef HPM_I2C_DRV_DEFAULT_TPM
11 #define HPM_I2C_DRV_DEFAULT_TPM (0U)
12 #endif
13 
14 #ifndef HPM_I2C_DRV_DEFAULT_SCL_RATIO
15 #define HPM_I2C_DRV_DEFAULT_SCL_RATIO (1U)
16 #endif
17 
18 #ifndef HPM_I2C_DRV_DEFAULT_RETRY_COUNT
19 #define HPM_I2C_DRV_DEFAULT_RETRY_COUNT (5000U)
20 #endif
21 
22 #define period_in_ns(freq) (1000000000UL / (freq))
23 
24 typedef struct {
25     uint32_t t_high;
26     uint32_t t_low;
27     uint16_t t_sp;
28     uint16_t t_sudat;
29     uint16_t t_hddat;
30     uint16_t t_sclhi_min1;
31     uint16_t t_sclhi_min2;
32     uint16_t t_sclratio;
33 } i2c_timing_t;
34 
i2c_configure_timing(uint32_t src_clk_in_hz,i2c_mode_t i2c_mode,i2c_timing_t * timing)35 static hpm_stat_t i2c_configure_timing(uint32_t src_clk_in_hz,
36                                        i2c_mode_t i2c_mode,
37                                        i2c_timing_t *timing)
38 {
39     switch (i2c_mode) {
40     /*
41      *          |Standard mode | Fast mode | Fast mode plus | Uint
42      * ---------+--------------+-----------+----------------+-------
43      *  t_high  |     4.0      |    0.6    |     0.26       |   us
44      *  t_low   |     4.7      |    1.3    |     0.5        |   us
45      *
46      */
47     case i2c_mode_fast:
48         timing->t_high = 600;
49         timing->t_low = 1300;
50         break;
51     case i2c_mode_fast_plus:
52         timing->t_high = 260;
53         timing->t_low = 500;
54         break;
55     case i2c_mode_normal:
56         timing->t_high = 4000;
57         timing->t_low = 4700;
58         break;
59     default:
60         return status_i2c_not_supported;
61     }
62 
63     /*
64      * Spike Suppression | Standard | Fast mode | Fast mode plus | Uint
65      *                   | mode     |           |                |
66      * ------------------+----------+-----------+----------------+-------
67      *    t_sp (min)     |    -     |  0 - 50   |    0 - 50      |   ns
68      *
69      * T_SP = 50ns / (25ns * (TPM + 1))
70      */
71     timing->t_sp = 50 / period_in_ns(src_clk_in_hz) / (HPM_I2C_DRV_DEFAULT_TPM + 1);
72 
73     /*
74      * Setup time       |Standard mode | Fast mode | Fast mode plus | Uint
75      * -----------------+--------------+-----------+----------------+-------
76      *  t_sudat (min)   |     250      |    100    |     50         |   ns
77      *
78      * Setup time = (2 * tpclk) + (2 + T_SP + T_SUDAT) * tpclk * (TPM + 1)
79      */
80     timing->t_sudat = (250 - 2 * period_in_ns(src_clk_in_hz)) / period_in_ns(src_clk_in_hz) - 2 - timing->t_sp;
81 
82     /*
83      * Hold time       |Standard mode | Fast mode | Fast mode plus | Uint
84      * ----------------+--------------+-----------+----------------+-------
85      *  t_hddata (min) |     300      |    300    |     0          |   ns
86      *
87      * Hold time = (2 * tpclk) + (2 + T_SP + T_HDDAT) * tpclk * (TPM + 1)
88      */
89     timing->t_hddat = (300 - 2 * period_in_ns(src_clk_in_hz)) / period_in_ns(src_clk_in_hz) - 2 - timing->t_sp;
90 
91     /*
92      * SCLK High period = (2 * tpclk) + (2 + T_SP + T_SCLHi) * tpclk * (TPM + 1) > t_high;
93      */
94     timing->t_sclhi_min1 = (timing->t_high - 2 * period_in_ns(src_clk_in_hz))
95         / (HPM_I2C_DRV_DEFAULT_TPM + 1) / period_in_ns(src_clk_in_hz) - 2 - timing->t_sp;
96 
97     /*
98      * SCLK Low period = (2 * tpclk) + (2 + T_SP + T_SCLHi * ratio) * tpclk * (TPM + 1) > t_low;
99      */
100     timing->t_sclhi_min2 = ((timing->t_low - 2 * period_in_ns(src_clk_in_hz))
101         / (HPM_I2C_DRV_DEFAULT_TPM + 1) / period_in_ns(src_clk_in_hz) - 2 - timing->t_sp)
102         / (timing->t_sclratio);
103 
104     return status_success;
105 }
106 
i2c_reset(I2C_Type * ptr)107 void i2c_reset(I2C_Type *ptr)
108 {
109     ptr->CTRL = 0;
110     ptr->CMD = I2C_CMD_RESET;
111     ptr->SETUP &= ~I2C_SETUP_IICEN_MASK;
112 }
113 
i2c_init_master(I2C_Type * ptr,uint32_t src_clk_in_hz,i2c_config_t * config)114 hpm_stat_t i2c_init_master(I2C_Type *ptr, uint32_t src_clk_in_hz, i2c_config_t *config)
115 {
116     hpm_stat_t stat = status_success;
117     i2c_timing_t timing = {0};
118 
119     i2c_reset(ptr);
120 
121     timing.t_sclratio = HPM_I2C_DRV_DEFAULT_SCL_RATIO;
122     stat = i2c_configure_timing(src_clk_in_hz, config->i2c_mode, &timing);
123     if (status_success != stat) {
124         return stat;
125     }
126 
127     ptr->TPM = I2C_TPM_TPM_SET(HPM_I2C_DRV_DEFAULT_TPM);
128 
129     ptr->SETUP = I2C_SETUP_T_SP_SET(timing.t_sp)
130         | I2C_SETUP_T_SUDAT_SET(timing.t_sudat)
131         | I2C_SETUP_T_HDDAT_SET(timing.t_hddat)
132         | I2C_SETUP_T_SCLRADIO_SET(timing.t_sclratio - 1)
133         | I2C_SETUP_T_SCLHI_SET(MAX(timing.t_sclhi_min1, timing.t_sclhi_min2))
134         | I2C_SETUP_ADDRESSING_SET(config->is_10bit_addressing)
135         | I2C_SETUP_IICEN_MASK
136         | I2C_SETUP_MASTER_MASK;
137 
138     return status_success;
139 }
140 
i2c_master_address_read(I2C_Type * ptr,const uint16_t device_address,uint8_t * addr,uint8_t addr_size_in_byte,uint8_t * buf,const uint32_t size_in_byte)141 hpm_stat_t i2c_master_address_read(I2C_Type *ptr, const uint16_t device_address,
142                                    uint8_t *addr, uint8_t addr_size_in_byte,
143                                    uint8_t *buf, const uint32_t size_in_byte)
144 {
145     hpm_stat_t stat = status_success;
146     uint32_t left;
147     uint32_t retry;
148 
149     ptr->CMD = I2C_CMD_RESET;
150 
151     ptr->CMD = I2C_CMD_CLEAR_FIFO;
152     ptr->CTRL = I2C_CTRL_PHASE_START_MASK
153         | I2C_CTRL_PHASE_STOP_MASK
154         | I2C_CTRL_PHASE_ADDR_MASK
155         | I2C_CTRL_PHASE_DATA_MASK
156         | I2C_CTRL_DIR_SET(I2C_DIR_MASTER_WRITE)
157         | I2C_CTRL_DATACNT_SET(addr_size_in_byte);
158 
159     ptr->ADDR = I2C_ADDR_ADDR_SET(device_address);
160 
161     left = addr_size_in_byte;
162     while (left) {
163         ptr->DATA = *(addr++);
164         left--;
165     }
166     ptr->CMD = I2C_CMD_ISSUE_DATA_TRANSMISSION;
167 
168     retry = 0;
169     while (!(ptr->STATUS & I2C_STATUS_CMPL_MASK)) {
170         if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
171             break;
172         }
173         retry++;
174     }
175     if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
176         return status_timeout;
177     }
178 
179     ptr->CMD = I2C_CMD_CLEAR_FIFO;
180     ptr->CTRL = I2C_CTRL_PHASE_START_MASK
181         | I2C_CTRL_PHASE_STOP_MASK
182         | I2C_CTRL_PHASE_ADDR_MASK
183         | I2C_CTRL_PHASE_DATA_MASK
184         | I2C_CTRL_DIR_SET(I2C_DIR_MASTER_READ)
185         | I2C_CTRL_DATACNT_SET(size_in_byte);
186     ptr->CMD = I2C_CMD_ISSUE_DATA_TRANSMISSION;
187 
188     retry = 0;
189     left = size_in_byte;
190     while (left) {
191         if (!(ptr->STATUS & I2C_STATUS_FIFOEMPTY_MASK)) {
192             *(buf++) = ptr->DATA;
193             left--;
194             retry = 0;
195         } else {
196             if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
197                 break;
198             }
199             retry++;
200         }
201     }
202 
203     if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
204         return status_timeout;
205     }
206 
207     retry = 0;
208     while (!(ptr->STATUS & I2C_STATUS_CMPL_MASK)) {
209         if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
210             break;
211         }
212         retry++;
213     }
214     if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
215         return status_timeout;
216     }
217     ptr->STATUS |= I2C_STATUS_CMPL_MASK;
218     return stat;
219 }
220 
i2c_master_address_write(I2C_Type * ptr,const uint16_t device_address,uint8_t * addr,uint8_t addr_size_in_byte,uint8_t * buf,const uint32_t size_in_byte)221 hpm_stat_t i2c_master_address_write(I2C_Type *ptr, const uint16_t device_address,
222                                     uint8_t *addr, uint8_t addr_size_in_byte,
223                                     uint8_t *buf, const uint32_t size_in_byte)
224 {
225     hpm_stat_t stat = status_success;
226     uint32_t left;
227     uint32_t retry;
228 
229     ptr->CMD = I2C_CMD_RESET;
230 
231     ptr->CMD = I2C_CMD_CLEAR_FIFO;
232     ptr->ADDR = I2C_ADDR_ADDR_SET(device_address);
233     ptr->CTRL = I2C_CTRL_PHASE_START_MASK
234         | I2C_CTRL_PHASE_STOP_MASK
235         | I2C_CTRL_PHASE_ADDR_MASK
236         | I2C_CTRL_PHASE_DATA_MASK
237         | I2C_CTRL_DIR_SET(I2C_DIR_MASTER_WRITE)
238         | I2C_CTRL_DATACNT_SET(size_in_byte + addr_size_in_byte);
239 
240     left = addr_size_in_byte;
241     while (left) {
242         ptr->DATA = *(addr++);
243         left--;
244     }
245     ptr->CMD = I2C_CMD_ISSUE_DATA_TRANSMISSION;
246 
247     retry = 0;
248     left = size_in_byte;
249     while (left) {
250         if (!(ptr->STATUS & I2C_STATUS_FIFOFULL_MASK)) {
251             ptr->DATA = *(buf++);
252             left--;
253             retry = 0;
254         } else {
255             if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
256                 break;
257             }
258             retry++;
259         }
260     }
261     if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
262         return status_timeout;
263     }
264 
265     retry = 0;
266     while (!(ptr->STATUS & I2C_STATUS_CMPL_MASK)) {
267         if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
268             break;
269         } else {
270             retry++;
271         }
272     }
273 
274     if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
275         return status_timeout;
276     }
277 
278     ptr->STATUS |= I2C_STATUS_CMPL_MASK;
279 
280     ptr->CMD = I2C_CMD_RESET;
281     return stat;
282 }
283 
i2c_master_read(I2C_Type * ptr,const uint16_t device_address,uint8_t * buf,const uint32_t size)284 hpm_stat_t i2c_master_read(I2C_Type *ptr, const uint16_t device_address,
285                            uint8_t *buf, const uint32_t size)
286 {
287     hpm_stat_t stat = status_success;
288     uint32_t left;
289     uint32_t retry;
290 
291     ptr->CMD = I2C_CMD_CLEAR_FIFO;
292     ptr->ADDR = I2C_ADDR_ADDR_SET(device_address);
293     ptr->CTRL = I2C_CTRL_PHASE_START_MASK
294         | I2C_CTRL_PHASE_STOP_MASK
295         | I2C_CTRL_PHASE_ADDR_MASK
296         | I2C_CTRL_PHASE_DATA_MASK
297         | I2C_CTRL_DIR_SET(I2C_DIR_MASTER_READ)
298         | I2C_CTRL_DATACNT_SET(size);
299     ptr->CMD = I2C_CMD_ISSUE_DATA_TRANSMISSION;
300 
301     retry = 0;
302     left = size;
303     while (left) {
304         if (!(ptr->STATUS & I2C_STATUS_FIFOEMPTY_MASK)) {
305             *(buf++) = ptr->DATA;
306             left--;
307             if (left) {
308                 ptr->CMD = I2C_CMD_ISSUE_DATA_TRANSMISSION;
309             }
310             retry = 0;
311         } else {
312             if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
313                 break;
314             }
315             retry++;
316         }
317     }
318     if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
319         return status_timeout;
320     }
321 
322     retry = 0;
323     while (!(ptr->STATUS & I2C_STATUS_CMPL_MASK)) {
324         if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
325             break;
326         }
327         retry++;
328     };
329     if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
330         return status_timeout;
331     }
332 
333     if (!(ptr->STATUS & I2C_STATUS_ADDRHIT_MASK)) {
334         /* I2C slave did not receive this transaction correctly. */
335         return status_fail;
336     }
337 
338     ptr->STATUS |= I2C_STATUS_CMPL_MASK | I2C_STATUS_ADDRHIT_MASK;
339 
340     ptr->INTEN = 0;
341     if (i2c_get_data_count(ptr)) {
342         return status_i2c_transmit_not_completed;
343     }
344 
345     return stat;
346 }
347 
i2c_master_write(I2C_Type * ptr,const uint16_t device_address,uint8_t * buf,const uint32_t size)348 hpm_stat_t i2c_master_write(I2C_Type *ptr, const uint16_t device_address,
349                             uint8_t *buf, const uint32_t size)
350 {
351     hpm_stat_t stat = status_success;
352     uint32_t retry;
353     uint32_t left;
354 
355     ptr->CMD = I2C_CMD_CLEAR_FIFO;
356     ptr->ADDR = I2C_ADDR_ADDR_SET(device_address);
357     ptr->CTRL = I2C_CTRL_PHASE_START_MASK
358         | I2C_CTRL_PHASE_STOP_MASK
359         | I2C_CTRL_PHASE_ADDR_MASK
360         | I2C_CTRL_PHASE_DATA_MASK
361         | I2C_CTRL_DIR_SET(I2C_DIR_MASTER_WRITE)
362         | I2C_CTRL_DATACNT_SET(size);
363 
364     retry = 0;
365     left = size;
366     while (left) {
367         if (!(ptr->STATUS & I2C_STATUS_FIFOFULL_MASK)) {
368             ptr->DATA = *(buf++);
369             left--;
370             ptr->CMD = I2C_CMD_ISSUE_DATA_TRANSMISSION;
371             retry = 0;
372         } else {
373             if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
374                 break;
375             }
376             retry++;
377         }
378     }
379     if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
380         return status_timeout;
381     }
382 
383     retry = 0;
384     while (!(ptr->STATUS & I2C_STATUS_CMPL_MASK)) {
385         if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
386             break;
387         }
388         retry++;
389     }
390     if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
391         return status_timeout;
392     }
393     ptr->STATUS |= I2C_STATUS_CMPL_MASK;
394 
395     ptr->INTEN = 0;
396     if (i2c_get_data_count(ptr)) {
397         return status_i2c_transmit_not_completed;
398     }
399 
400     ptr->CMD = I2C_CMD_RESET;
401     return stat;
402 }
403 
i2c_init_slave(I2C_Type * ptr,uint32_t src_clk_in_hz,i2c_config_t * config,const uint16_t slave_address)404 hpm_stat_t i2c_init_slave(I2C_Type *ptr, uint32_t src_clk_in_hz,
405                           i2c_config_t *config, const uint16_t slave_address)
406 {
407     hpm_stat_t stat = status_success;
408     i2c_timing_t timing = {0};
409 
410     i2c_reset(ptr);
411 
412     ptr->ADDR = I2C_ADDR_ADDR_SET(slave_address);
413 
414     timing.t_sclratio = HPM_I2C_DRV_DEFAULT_SCL_RATIO;
415     stat = i2c_configure_timing(src_clk_in_hz, config->i2c_mode, &timing);
416     if (status_success != stat) {
417         return stat;
418     }
419 
420     ptr->TPM = I2C_TPM_TPM_SET(HPM_I2C_DRV_DEFAULT_TPM);
421 
422     ptr->SETUP = I2C_SETUP_T_SP_SET(timing.t_sp)
423         | I2C_SETUP_T_SUDAT_SET(timing.t_sudat)
424         | I2C_SETUP_T_HDDAT_SET(timing.t_hddat)
425         | I2C_SETUP_T_SCLRADIO_SET(timing.t_sclratio - 1)
426         | I2C_SETUP_T_SCLHI_SET(MAX(timing.t_sclhi_min1, timing.t_sclhi_min2))
427         | I2C_SETUP_ADDRESSING_SET(config->is_10bit_addressing)
428         | I2C_SETUP_IICEN_MASK;
429 
430     return stat;
431 }
432 
i2c_slave_write(I2C_Type * ptr,uint8_t * buf,const uint32_t size)433 hpm_stat_t i2c_slave_write(I2C_Type *ptr, uint8_t *buf, const uint32_t size)
434 {
435     volatile uint32_t status;
436     uint32_t retry;
437     uint32_t left;
438 
439     retry = 0;
440     left = size;
441     while (left) {
442         status = ptr->STATUS;
443         if (!(status & I2C_STATUS_FIFOFULL_MASK)) {
444             ptr->DATA = *(buf++);
445             left--;
446             retry = 0;
447         } else {
448             if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
449                 break;
450             }
451             retry++;
452         }
453     }
454     if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
455         return status_timeout;
456     }
457 
458     retry = 0;
459     while (!(ptr->STATUS & I2C_STATUS_CMPL_MASK)) {
460         if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
461             break;
462         }
463         retry++;
464     }
465     if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
466         return status_timeout;
467     }
468     /* clear status, CMPL must to be cleared at slave mode before next transaction */
469     i2c_clear_status(ptr, ptr->STATUS);
470 
471     if (i2c_get_data_count(ptr) != size) {
472         return status_i2c_transmit_not_completed;
473     }
474 
475     return status_success;
476 }
477 
i2c_slave_read(I2C_Type * ptr,uint8_t * buf,const uint32_t size)478 hpm_stat_t i2c_slave_read(I2C_Type *ptr,
479                           uint8_t *buf,
480                           const uint32_t size)
481 {
482     volatile uint32_t status;
483     uint32_t retry;
484     uint32_t left;
485 
486     retry = 0;
487     left = size;
488     while (left) {
489         status = ptr->STATUS;
490         if (!(status & I2C_STATUS_FIFOEMPTY_MASK)) {
491             *(buf++) = ptr->DATA;
492             left--;
493             retry = 0;
494         } else {
495             if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
496                 break;
497             }
498             retry++;
499         }
500     }
501     if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
502         return status_timeout;
503     }
504 
505     retry = 0;
506     while (!(ptr->STATUS & I2C_STATUS_CMPL_MASK)) {
507         if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
508             break;
509         }
510         retry++;
511     }
512     if (retry > HPM_I2C_DRV_DEFAULT_RETRY_COUNT) {
513         return status_timeout;
514     }
515     /* clear status, CMPL must to be cleared at slave mode before next transaction */
516     i2c_clear_status(ptr, ptr->STATUS);
517 
518     if (i2c_get_data_count(ptr) != size) {
519         return status_i2c_transmit_not_completed;
520     }
521 
522     return status_success;
523 }
524 
i2c_master_start_dma_write(I2C_Type * i2c_ptr,const uint16_t device_address,uint32_t size)525 void i2c_master_start_dma_write(I2C_Type *i2c_ptr, const uint16_t device_address, uint32_t size)
526 {
527     i2c_ptr->ADDR = I2C_ADDR_ADDR_SET(device_address);
528     i2c_ptr->CTRL = I2C_CTRL_PHASE_START_MASK
529         | I2C_CTRL_PHASE_STOP_MASK
530         | I2C_CTRL_PHASE_ADDR_MASK
531         | I2C_CTRL_PHASE_DATA_MASK
532         | I2C_CTRL_DIR_SET(I2C_DIR_MASTER_WRITE)
533         | I2C_CTRL_DATACNT_SET(size);
534 
535     i2c_ptr->SETUP |= I2C_SETUP_DMAEN_MASK;
536 
537     i2c_ptr->CMD = I2C_CMD_ISSUE_DATA_TRANSMISSION;
538 }
539 
i2c_master_start_dma_read(I2C_Type * i2c_ptr,const uint16_t device_address,uint32_t size)540 void i2c_master_start_dma_read(I2C_Type *i2c_ptr, const uint16_t device_address, uint32_t size)
541 {
542     i2c_ptr->ADDR = I2C_ADDR_ADDR_SET(device_address);
543     i2c_ptr->CTRL = I2C_CTRL_PHASE_START_MASK
544         | I2C_CTRL_PHASE_STOP_MASK
545         | I2C_CTRL_PHASE_ADDR_MASK
546         | I2C_CTRL_PHASE_DATA_MASK
547         | I2C_CTRL_DIR_SET(I2C_DIR_MASTER_READ)
548         | I2C_CTRL_DATACNT_SET(size);
549 
550     i2c_ptr->SETUP |= I2C_SETUP_DMAEN_MASK;
551 
552     i2c_ptr->CMD = I2C_CMD_ISSUE_DATA_TRANSMISSION;
553 }
554 
i2c_slave_dma_transfer(I2C_Type * i2c_ptr,uint32_t size)555 void i2c_slave_dma_transfer(I2C_Type *i2c_ptr, uint32_t size)
556 {
557     i2c_ptr->CTRL |= I2C_CTRL_DATACNT_SET(size);
558 
559     i2c_ptr->SETUP |= I2C_SETUP_DMAEN_MASK;
560 }
561