1 /*
2  * Copyright (c) 2022-2024 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <rtthread.h>
9 #include <rtdevice.h>
10 #include <rtdbg.h>
11 #ifdef BSP_USING_I2C
12 #include "drv_i2c.h"
13 #include "hpm_i2c_drv.h"
14 #include "hpm_dma_mgr.h"
15 #include "hpm_dmamux_drv.h"
16 #include "hpm_l1c_drv.h"
17 #include "board.h"
18 
19 
20 #ifdef RT_USING_I2C
21 
22 #define HPM_RTT_DRV_RETRY_TIMEOUT (1000000)
23 
24 #ifndef HPM_I2C_DRV_DEFAULT_RETRY_COUNT
25 #define HPM_I2C_DRV_DEFAULT_RETRY_COUNT (5000U)
26 #endif
27 
28 struct hpm_i2c
29 {
30     struct rt_i2c_bus_device bus;
31     I2C_Type *base;
32     clock_name_t clk_name;
33     char *bus_name;
34     rt_sem_t xfer_sem;
35     rt_bool_t enable_dma;
36     rt_uint8_t dmamux;
37     dma_resource_t dma;
38     rt_uint8_t i2c_irq;
39     rt_uint8_t is_read;
40 };
41 
42 static struct hpm_i2c hpm_i2cs[] =
43 {
44 #if defined(BSP_USING_I2C0)
45     {
46         .base = HPM_I2C0,
47         .bus_name = "i2c0",
48         .clk_name = clock_i2c0,
49 #if defined(BSP_I2C0_USING_DMA)
50         .enable_dma = RT_TRUE,
51 #endif
52         .dmamux = HPM_DMA_SRC_I2C0,
53         .i2c_irq = IRQn_I2C0,
54     },
55 #endif
56 #if defined(BSP_USING_I2C1)
57     {
58         .base = HPM_I2C1,
59         .bus_name = "i2c1",
60         .clk_name = clock_i2c1,
61 #if defined(BSP_I2C1_USING_DMA)
62         .enable_dma = RT_TRUE,
63 #endif
64         .dmamux = HPM_DMA_SRC_I2C1,
65         .i2c_irq = IRQn_I2C1,
66     },
67 #endif
68 #if defined(BSP_USING_I2C2)
69     {
70         .base = HPM_I2C2,
71         .bus_name = "i2c2",
72         .clk_name = clock_i2c2,
73 #if defined(BSP_I2C2_USING_DMA)
74         .enable_dma = RT_TRUE,
75 #endif
76         .dmamux = HPM_DMA_SRC_I2C2,
77         .i2c_irq = IRQn_I2C2,
78     },
79 #endif
80 #if defined(BSP_USING_I2C3)
81     {
82         .base = HPM_I2C3,
83         .bus_name = "i2c3",
84         .clk_name = clock_i2c3,
85 #if defined(BSP_I2C3_USING_DMA)
86         .enable_dma = RT_TRUE,
87 #endif
88         .dmamux = HPM_DMA_SRC_I2C3,
89         .i2c_irq = IRQn_I2C3,
90     },
91 #endif
92 };
93 static hpm_stat_t i2c_transfer(I2C_Type *ptr, const uint16_t device_address,
94                                     uint8_t *buf, const uint32_t size,  uint16_t flags);
95 static rt_ssize_t hpm_i2c_master_transfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num);
96 static hpm_stat_t i2c_tx_trigger_dma(DMA_Type *dma_ptr, uint8_t ch_num, I2C_Type *i2c_ptr, uint32_t src, uint32_t size);
97 static hpm_stat_t i2c_rx_trigger_dma(DMA_Type *dma_ptr, uint8_t ch_num, I2C_Type *i2c_ptr, uint32_t dst, uint32_t size);
98 
99 struct rt_i2c_bus_device_ops hpm_i2c_ops =
100 {
101     hpm_i2c_master_transfer,
102     RT_NULL,
103     RT_NULL
104 };
105 
handle_i2c_isr(I2C_Type * ptr)106 static inline void handle_i2c_isr(I2C_Type *ptr)
107 {
108     volatile uint32_t irq_status;
109     RT_ASSERT(ptr != RT_NULL);
110     rt_base_t level;
111     level = rt_hw_interrupt_disable();
112     irq_status = i2c_get_status(ptr);
113     if (irq_status & I2C_EVENT_TRANSACTION_COMPLETE)
114     {
115         for (uint32_t i = 0; i < sizeof(hpm_i2cs) / sizeof(hpm_i2cs[0]); i++)
116         {
117             if (hpm_i2cs[i].base == ptr)
118             {
119                 rt_sem_release(hpm_i2cs[i].xfer_sem);
120             }
121         }
122         i2c_disable_irq(ptr, I2C_EVENT_TRANSACTION_COMPLETE);
123         i2c_clear_status(ptr, I2C_EVENT_TRANSACTION_COMPLETE);
124     }
125     rt_hw_interrupt_enable(level);
126 }
127 
128 #if defined(BSP_USING_I2C0)
i2c0_isr(void)129 void i2c0_isr(void)
130 {
131     handle_i2c_isr(HPM_I2C0);
132 }
133 SDK_DECLARE_EXT_ISR_M(IRQn_I2C0, i2c0_isr);
134 #endif
135 
136 #if defined(BSP_USING_I2C1)
i2c1_isr(void)137 void i2c1_isr(void)
138 {
139     handle_i2c_isr(HPM_I2C1);
140 }
141 SDK_DECLARE_EXT_ISR_M(IRQn_I2C1, i2c1_isr);
142 #endif
143 
144 #if defined(BSP_USING_I2C2)
i2c2_isr(void)145 void i2c2_isr(void)
146 {
147     handle_i2c_isr(HPM_I2C2);
148 }
149 SDK_DECLARE_EXT_ISR_M(IRQn_I2C2, i2c2_isr);
150 #endif
151 
152 #if defined(BSP_USING_I2C3)
i2c3_isr(void)153 void i2c3_isr(void)
154 {
155     handle_i2c_isr(HPM_I2C3);
156 }
157 SDK_DECLARE_EXT_ISR_M(IRQn_I2C3, i2c3_isr);
158 #endif
159 
i2c_tx_trigger_dma(DMA_Type * dma_ptr,uint8_t ch_num,I2C_Type * i2c_ptr,uint32_t src,uint32_t size)160 static hpm_stat_t i2c_tx_trigger_dma(DMA_Type *dma_ptr, uint8_t ch_num, I2C_Type *i2c_ptr, uint32_t src, uint32_t size)
161 {
162     dma_handshake_config_t config;
163 
164     dma_default_handshake_config(dma_ptr, &config);
165     config.ch_index = ch_num;
166     config.dst = (uint32_t)&i2c_ptr->DATA;
167     config.dst_fixed = true;
168     config.src = src;
169     config.src_fixed = false;
170     config.data_width = DMA_TRANSFER_WIDTH_BYTE;
171     config.size_in_byte = size;
172 
173     return dma_setup_handshake(dma_ptr, &config, true);
174 }
175 
i2c_rx_trigger_dma(DMA_Type * dma_ptr,uint8_t ch_num,I2C_Type * i2c_ptr,uint32_t dst,uint32_t size)176 static hpm_stat_t i2c_rx_trigger_dma(DMA_Type *dma_ptr, uint8_t ch_num, I2C_Type *i2c_ptr, uint32_t dst, uint32_t size)
177 {
178     dma_handshake_config_t config;
179 
180     dma_default_handshake_config(dma_ptr, &config);
181     config.ch_index = ch_num;
182     config.dst = dst;
183     config.dst_fixed = false;
184     config.src = (uint32_t)&i2c_ptr->DATA;
185     config.src_fixed = true;
186     config.data_width = DMA_TRANSFER_WIDTH_BYTE;
187     config.size_in_byte = size;
188 
189     return dma_setup_handshake(dma_ptr, &config, true);
190 }
191 
i2c_dma_channel_tc_callback(DMA_Type * ptr,uint32_t channel,void * user_data)192 void i2c_dma_channel_tc_callback(DMA_Type *ptr, uint32_t channel, void *user_data)
193 {
194     struct hpm_i2c *i2c = (struct hpm_i2c *)user_data;
195     RT_ASSERT(i2c != RT_NULL);
196     RT_ASSERT(ptr != RT_NULL);
197     rt_base_t level;
198     level = rt_hw_interrupt_disable();
199     if ((i2c->dma.base == ptr) && i2c->dma.channel == channel)
200     {
201         dma_mgr_disable_chn_irq(&i2c->dma, DMA_MGR_INTERRUPT_MASK_TC);
202         if (i2c->is_read == true)
203         {
204             rt_sem_release(i2c->xfer_sem);
205         }
206     }
207     rt_hw_interrupt_enable(level);
208 }
209 
hpm_i2c_master_transfer(struct rt_i2c_bus_device * bus,struct rt_i2c_msg msgs[],rt_uint32_t num)210 static rt_ssize_t hpm_i2c_master_transfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num)
211 {
212     RT_ASSERT(bus != RT_NULL);
213     RT_ASSERT(msgs != RT_NULL);
214 
215     struct rt_i2c_msg *msg;
216     struct hpm_i2c *i2c_info = (struct hpm_i2c *)bus;
217 
218     hpm_stat_t i2c_stat = status_success;
219     rt_size_t ret = 0;
220     rt_uint32_t i;
221     rt_uint8_t *raw_alloc_buf = RT_NULL;
222     rt_uint8_t *aligned_buf = RT_NULL;
223     rt_uint8_t *dummy_buf = RT_NULL;
224     rt_uint32_t aligned_len = 0;
225     rt_uint32_t remaining_size = 0;
226     rt_uint32_t transfer_len;
227     for (i = 0; i < num; i++)
228     {
229         msg = &msgs[i];
230         remaining_size = msg->len;
231         if ((msg->len > 0) && (i2c_info->enable_dma))
232         {
233             aligned_len = (msg->len + HPM_L1C_CACHELINE_SIZE - 1U) & ~(HPM_L1C_CACHELINE_SIZE - 1U);
234             if (l1c_dc_is_enabled())
235             {
236                 if (msg->flags & RT_I2C_RD)
237                 {
238                     /* The allocated pointer is always RT_ALIGN_SIZE aligned */
239                     raw_alloc_buf = (uint8_t*)rt_malloc(aligned_len + HPM_L1C_CACHELINE_SIZE - RT_ALIGN_SIZE);
240                     RT_ASSERT(raw_alloc_buf != RT_NULL);
241                 }
242                 else
243                 {
244                     aligned_buf = (uint8_t*)HPM_L1C_CACHELINE_ALIGN_UP((uint32_t)raw_alloc_buf);
245                     /* The allocated pointer is always RT_ALIGN_SIZE aligned */
246                     raw_alloc_buf = (uint8_t*)rt_malloc(aligned_len + HPM_L1C_CACHELINE_SIZE - RT_ALIGN_SIZE);
247                     RT_ASSERT(raw_alloc_buf != RT_NULL);
248                     aligned_buf = (uint8_t*)HPM_L1C_CACHELINE_ALIGN_UP((uint32_t)raw_alloc_buf);
249                     rt_memcpy(aligned_buf, msg->buf, msg->len);
250                     l1c_dc_flush((uint32_t)aligned_buf, aligned_len);
251                 }
252             }
253         }
254         else
255         {
256             aligned_buf = (uint8_t*) msg->buf;
257         }
258 
259         if (msg->flags & RT_I2C_ADDR_10BIT)
260         {
261             i2c_enable_10bit_address_mode(i2c_info->base, true);
262         }
263         else
264         {
265             i2c_enable_10bit_address_mode(i2c_info->base, false);
266         }
267         dummy_buf = aligned_buf;
268         if (msg->flags & RT_I2C_RD)
269         {
270             /* maybe probe i2c device */
271             if (msg->len == 0)
272             {
273                 i2c_stat = i2c_master_read(i2c_info->base, msg->addr, dummy_buf, remaining_size);
274             }
275             else
276             {
277                 while (remaining_size)
278                 {
279                     transfer_len = MIN(I2C_SOC_TRANSFER_COUNT_MAX, remaining_size);
280                     if ((i2c_info->enable_dma))
281                     {
282                         /* sequential transfer now is not support dma */
283                         if ((msg->flags & RT_I2C_NO_START) || (msg->flags & RT_I2C_NO_STOP) ||
284                             (msg->flags & RT_I2C_NO_READ_ACK) || (msg->flags & RT_I2C_NO_READ_ACK) ) {
285                             i2c_stat = status_invalid_argument;
286                             break;
287                         }
288                         i2c_info->is_read = true;
289                         i2c_enable_irq(i2c_info->base, I2C_EVENT_TRANSACTION_COMPLETE);
290                         dmamux_config(HPM_DMAMUX, i2c_info->dma.channel, i2c_info->dmamux, true);
291                         i2c_stat = i2c_rx_trigger_dma(i2c_info->dma.base, i2c_info->dma.channel, i2c_info->base,
292                                             core_local_mem_to_sys_address(0, (uint32_t) dummy_buf), transfer_len);
293                         if (i2c_stat != status_success)
294                         {
295                             break;
296                         }
297                         i2c_stat = i2c_master_start_dma_read(i2c_info->base, msg->addr, msg->len);
298                         if (i2c_stat != status_success)
299                         {
300                             break;
301                         }
302                         rt_sem_take(i2c_info->xfer_sem, RT_WAITING_FOREVER);
303                     }
304                     else
305                     {
306                         i2c_master_transfer(i2c_info->base, msg->addr, dummy_buf, transfer_len, msg->flags);
307                     }
308                     dummy_buf += transfer_len;
309                     remaining_size -= transfer_len;
310                 }
311                 if (raw_alloc_buf != RT_NULL)
312                 {
313                     l1c_dc_invalidate((uint32_t) aligned_buf, aligned_len);
314                     rt_memcpy(msg->buf, aligned_buf, msg->len);
315                     rt_free(raw_alloc_buf);
316                     raw_alloc_buf = RT_NULL;
317                     aligned_buf = RT_NULL;
318                 }
319             }
320         }
321         else
322         {
323             /* maybe probe i2c device */
324             if (msg->len == 0)
325             {
326                 i2c_stat = i2c_master_write(i2c_info->base, msg->addr, dummy_buf, remaining_size);
327             }
328             else
329             {
330                 while (remaining_size)
331                 {
332                     transfer_len = MIN(I2C_SOC_TRANSFER_COUNT_MAX, remaining_size);
333                     if (i2c_info->enable_dma)
334                     {
335                         /* sequential transfer now is not support dma */
336                         if ((msg->flags & RT_I2C_NO_START) || (msg->flags & RT_I2C_NO_STOP) ||
337                             (msg->flags & RT_I2C_NO_READ_ACK) || (msg->flags & RT_I2C_NO_READ_ACK) ) {
338                             i2c_stat = status_invalid_argument;
339                             break;
340                         }
341                         i2c_info->is_read = false;
342                         i2c_enable_irq(i2c_info->base, I2C_EVENT_TRANSACTION_COMPLETE);
343                         dmamux_config(HPM_DMAMUX, i2c_info->dma.channel, i2c_info->dmamux, true);
344                         i2c_stat = i2c_tx_trigger_dma(i2c_info->dma.base, i2c_info->dma.channel, i2c_info->base,
345                                             core_local_mem_to_sys_address(0, (uint32_t) dummy_buf), transfer_len);
346                         if (i2c_stat != status_success)
347                         {
348                             break;
349                         }
350                         i2c_stat = i2c_master_start_dma_write(i2c_info->base, msg->addr, msg->len);
351                         if (i2c_stat != status_success)
352                         {
353                             break;
354                         }
355                         rt_sem_take(i2c_info->xfer_sem, RT_WAITING_FOREVER);
356                     }
357                     else
358                     {
359                         i2c_master_transfer(i2c_info->base, msg->addr, dummy_buf, transfer_len, msg->flags);
360                     }
361                     dummy_buf += transfer_len;
362                     remaining_size -= transfer_len;
363                 }
364                 if (raw_alloc_buf != RT_NULL)
365                 {
366                     rt_free(raw_alloc_buf);
367                     raw_alloc_buf = RT_NULL;
368                     aligned_buf = RT_NULL;
369                 }
370             }
371         }
372         if (i2c_stat != status_success)
373         {
374             break;
375         }
376     }
377 
378     if (i2c_stat != status_success)
379     {
380         return ret;
381     }
382 
383     ret = i;
384     return ret;
385 }
386 
387 
rt_hw_i2c_init(void)388 int rt_hw_i2c_init(void)
389 {
390     rt_err_t ret = RT_EOK;
391     hpm_stat_t stat;
392     i2c_config_t config;
393     rt_uint32_t freq;
394     char sem_name[RT_NAME_MAX];
395 
396     for (uint32_t i = 0; i < sizeof(hpm_i2cs) / sizeof(hpm_i2cs[0]); i++) {
397         init_i2c_pins(hpm_i2cs[i].base);
398         clock_add_to_group(hpm_i2cs[i].clk_name, 0);
399         clock_set_source_divider(hpm_i2cs[i].clk_name, clk_src_osc24m, 1U);
400 
401         config.i2c_mode = i2c_mode_normal;
402         config.is_10bit_addressing = false;
403         freq = clock_get_frequency(hpm_i2cs[i].clk_name);
404         stat = i2c_init_master(hpm_i2cs[i].base, freq, &config);
405         if (stat != status_success) {
406             LOG_E("rt i2c device %s init failed", hpm_i2cs[i].bus_name);
407         }
408 
409         hpm_i2cs[i].bus.ops = &hpm_i2c_ops;
410         if (hpm_i2cs[i].enable_dma)
411         {
412             stat = dma_mgr_request_resource(&hpm_i2cs[i].dma);
413             if (stat != status_success)
414             {
415                 return -RT_ERROR;
416             }
417             dma_mgr_install_chn_tc_callback(&hpm_i2cs[i].dma, i2c_dma_channel_tc_callback, (void *)&hpm_i2cs[i]);
418             dma_mgr_enable_dma_irq_with_priority(&hpm_i2cs[i].dma, 1);
419             intc_m_enable_irq_with_priority(hpm_i2cs[i].i2c_irq, 2);
420             i2c_disable_irq(hpm_i2cs[i].base, I2C_EVENT_TRANSACTION_COMPLETE);
421             rt_sprintf(sem_name, "%s_s", hpm_i2cs[i].bus_name);
422             hpm_i2cs[i].xfer_sem = rt_sem_create(sem_name, 0, RT_IPC_FLAG_PRIO);
423             if (hpm_i2cs[i].xfer_sem == RT_NULL)
424             {
425                 ret = RT_ENOMEM;
426                 break;
427             }
428         }
429         ret = rt_i2c_bus_device_register(&hpm_i2cs[i].bus, hpm_i2cs[i].bus_name);
430         if (ret != RT_EOK) {
431             LOG_E("rt i2c device %s register failed, status=%d\n", hpm_i2cs[i].bus_name, ret);
432         }
433     }
434 
435     return ret;
436 }
437 INIT_DEVICE_EXPORT(rt_hw_i2c_init);
438 
439 #endif /* RT_USING_I2C */
440 
441 #endif /*BSP_USING_I2C*/
442 
443