1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2021-01-13     Lyons        first version
9  * 2021-06-23     RiceChen     refactor
10  */
11 
12 #include <rthw.h>
13 #include <rtdevice.h>
14 
15 #ifdef BSP_USING_I2C
16 
17 #define LOG_TAG              "drv.i2c"
18 #include <drv_log.h>
19 
20 #if !defined(BSP_USING_I2C1) && !defined(BSP_USING_I2C2) && !defined(BSP_USING_I2C3) && !defined(BSP_USING_I2C4)
21 #error "Please define at least one BSP_USING_I2Cx"
22 #endif
23 
24 #include "fsl_iomuxc.h"
25 #include "drv_i2c.h"
26 
27 static struct imx6ull_i2c_config i2c_config[] =
28 {
29 #ifdef BSP_USING_I2C1
30     I2C1_BUS_CONFIG,
31 #endif
32 #ifdef BSP_USING_I2C2
33     I2C2_BUS_CONFIG,
34 #endif
35 #ifdef BSP_USING_I2C3
36     I2C3_BUS_CONFIG,
37 #endif
38 #ifdef BSP_USING_I2C4
39     I2C4_BUS_CONFIG,
40 #endif
41 };
42 
43 static struct imx6ull_i2c_bus i2c_obj[sizeof(i2c_config) / sizeof(i2c_config[0])];
44 static char i2c_buff_temp[4][1024];
45 extern uint32_t I2C_GetInstance(I2C_Type *base);
46 
47 #ifdef IMX_I2C_IRQ_MODE
48 static uint32_t g_MasterCompletionFlag[4] = {0,0,0,0};
i2c_master_callback(I2C_Type * base,i2c_master_handle_t * handle,status_t status,void * userData)49 static void i2c_master_callback(I2C_Type *base, i2c_master_handle_t *handle, status_t status, void *userData)
50 {
51     /* Signal transfer success when received success status. */
52     struct imx6ull_i2c_config *config;
53 
54     config = (struct imx6ull_i2c_config*)userData;
55 
56     uint32_t instance = I2C_GetInstance(config->hw_base);
57     if (status == kStatus_Success)
58     {
59         g_MasterCompletionFlag[instance-1] = 1;
60     }
61 }
62 #endif
63 
imx6ull_i2c_mst_xfer(struct rt_i2c_bus_device * bus,struct rt_i2c_msg msgs[],rt_uint32_t num)64 static rt_ssize_t imx6ull_i2c_mst_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num)
65 {
66     rt_ssize_t i = 0;
67     struct imx6ull_i2c_bus *i2c_bus = RT_NULL;
68     static i2c_master_transfer_t xfer = {0};
69     RT_ASSERT(bus != RT_NULL);
70 #ifdef IMX_I2C_IRQ_MODE
71     uint32_t timeout_cnt = 100;
72 #endif
73     uint32_t instance = 0;
74 
75     i2c_bus = (struct imx6ull_i2c_bus *)bus;
76     instance = I2C_GetInstance(i2c_bus->config->hw_base);
77     for(i = 0 ;i < num; i++)
78     {
79         if(msgs[i].flags & RT_I2C_RD)
80         {
81             xfer.flags = kI2C_TransferNoStartFlag;
82             xfer.slaveAddress = msgs[i].addr;
83             xfer.direction = kI2C_Read;
84             xfer.subaddress = 0;
85             xfer.subaddressSize = 0;
86             xfer.data = (uint8_t *volatile)i2c_buff_temp[instance - 1];
87             xfer.dataSize = msgs[i].len ;
88 
89 #ifdef IMX_I2C_IRQ_MODE
90             I2C_MasterTransferNonBlocking(i2c_bus->config->I2C, &i2c_bus->config->master_handle,&xfer);
91             while(!g_MasterCompletionFlag[instance - 1])
92             {
93                 rt_thread_delay(1);
94                 timeout_cnt--;
95                 if(timeout_cnt == 0)
96                 {
97                     break;
98                 }
99             }
100             timeout_cnt = 100;
101             g_MasterCompletionFlag[instance - 1] = 0;
102 #else
103             I2C_MasterTransferBlocking(i2c_bus->config->I2C, &xfer);
104 #endif
105             rt_memcpy(msgs[i].buf,i2c_buff_temp[instance - 1],msgs[i].len);
106         }
107         else
108         {
109             xfer.flags = kI2C_TransferNoStartFlag;
110             xfer.slaveAddress = msgs[i].addr;
111             xfer.direction = kI2C_Write;
112             xfer.subaddress = 0;
113             xfer.subaddressSize = 0;
114             xfer.data = (uint8_t *volatile)i2c_buff_temp[instance - 1];
115             xfer.dataSize = msgs[i].len;
116             rt_memcpy(i2c_buff_temp[instance - 1],msgs[i].buf,msgs[i].len);
117 
118 #ifdef IMX_I2C_IRQ_MODE
119             I2C_MasterTransferNonBlocking(i2c_bus->config->I2C, &i2c_bus->config->master_handle,&xfer);
120             while(!g_MasterCompletionFlag[instance - 1])
121             {
122                 timeout_cnt--;
123                 rt_thread_delay(1);
124                 if(timeout_cnt == 0)
125                 {
126                     break;
127                 }
128             }
129             timeout_cnt = 100;
130             g_MasterCompletionFlag[instance - 1] = 0;
131 #else
132             I2C_MasterTransferBlocking(i2c_bus->config->I2C, &xfer);
133 #endif
134         }
135     }
136 
137     return i;
138 }
139 
imx6ull_i2c_bus_control(struct rt_i2c_bus_device * bus,rt_uint32_t cmd,rt_uint32_t arg)140 static rt_err_t imx6ull_i2c_bus_control(struct rt_i2c_bus_device *bus, rt_uint32_t cmd, rt_uint32_t arg)
141 {
142     return RT_EOK;
143 }
144 
imx6ull_i2c_gpio_init(struct imx6ull_i2c_bus * bus)145 static rt_err_t imx6ull_i2c_gpio_init(struct imx6ull_i2c_bus *bus)
146 {
147     struct imx6ull_i2c_bus *i2c_bus = RT_NULL;
148 
149     i2c_bus = (struct imx6ull_i2c_bus *)bus;
150 
151     imx6ull_gpio_init(&i2c_bus->config->scl_gpio);
152     imx6ull_gpio_init(&i2c_bus->config->sda_gpio);
153     return RT_EOK;
154 
155 }
156 
157 #ifdef RT_USING_DEVICE_OPS
158 static const struct rt_i2c_bus_device_ops imx6ull_i2c_ops =
159 {
160     .master_xfer = imx6ull_i2c_mst_xfer,
161     .slave_xfer = RT_NULL,
162     .i2c_bus_control = imx6ull_i2c_bus_control,
163 };
164 #endif
165 
166 extern void I2C_DriverIRQHandler(int irq, void *base);
rt_hw_i2c_init(void)167 int rt_hw_i2c_init(void)
168 {
169     rt_uint16_t obj_num = 0;
170     rt_uint32_t src_clock;
171     i2c_master_config_t masterConfig = {0};
172 
173     obj_num = sizeof(i2c_config) / sizeof(i2c_config[0]);
174 
175     src_clock = (CLOCK_GetFreq(kCLOCK_IpgClk) / (CLOCK_GetDiv(kCLOCK_PerclkDiv) + 1U));
176 
177     for(int i = 0; i < obj_num; i++)
178     {
179         i2c_obj[i].config = &i2c_config[i];
180         i2c_obj[i].config->hw_base = i2c_obj[i].config->I2C;
181         i2c_obj[i].config->I2C = (I2C_Type *)imx6ull_get_periph_vaddr((rt_uint32_t)i2c_obj[i].config->hw_base);
182         i2c_obj[i].parent.ops = &imx6ull_i2c_ops;
183         imx6ull_i2c_gpio_init(&i2c_obj[i]);
184 
185         I2C_MasterGetDefaultConfig(&masterConfig);
186         masterConfig.baudRate_Bps = i2c_config[i].baud_rate;
187 
188         CLOCK_EnableClock(i2c_obj[i].config->clk_ip_name);
189 
190         I2C_MasterInit(i2c_obj[i].config->I2C, &masterConfig, src_clock);
191 
192         rt_i2c_bus_device_register(&i2c_obj[i].parent, i2c_obj[i].config->name);
193 
194 #ifdef IMX_I2C_IRQ_MODE
195         I2C_MasterTransferCreateHandle(i2c_obj[i].config->hw_base, &i2c_obj[i].config->master_handle, i2c_master_callback, i2c_obj[i].config);
196         rt_hw_interrupt_install(i2c_obj[i].config->irq_num, (rt_isr_handler_t)I2C_DriverIRQHandler, i2c_obj[i].config, i2c_obj[i].config->name);
197 #endif
198     }
199 
200     return RT_EOK;
201 }
202 INIT_DEVICE_EXPORT(rt_hw_i2c_init);
203 
204 #endif
205