1 /*
2  * Copyright (c) 2006-2024 RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2023-08-21     hywing       The first version
9  */
10 
11 #include <rtdevice.h>
12 #include "fsl_lpi2c.h"
13 #include "fsl_lpi2c_edma.h"
14 #include "fsl_edma.h"
15 
16 
17 #ifdef RT_USING_I2C
18 
19 #define DBG_TAG    "drv.i2c"
20 #define DBG_LVL    DBG_INFO
21 #include <rtdbg.h>
22 
23 enum
24 {
25 #ifdef BSP_USING_I2C0
26     I2C0_INDEX,
27 #endif
28 #ifdef BSP_USING_I2C1
29     I2C1_INDEX,
30 #endif
31 #ifdef BSP_USING_I2C2
32     I2C2_INDEX,
33 #endif
34 #ifdef BSP_USING_I2C3
35     I2C3_INDEX,
36 #endif
37 };
38 
39 
40 struct lpc_i2c_bus
41 {
42     struct rt_i2c_bus_device    parent;
43     LPI2C_Type                  *I2C;
44     clock_attach_id_t           clock_attach_id;
45     clock_div_name_t            clock_div_name;
46     clock_name_t                clock_src;
47     uint32_t                    baud;
48     char                        *name;
49 };
50 
51 
52 struct lpc_i2c_bus lpc_obj[] =
53 {
54 #ifdef BSP_USING_I2C0
55         {
56             .I2C = LPI2C0,
57             .baud = 100000U,
58 #if (defined(CPU_MCXA346VLH) || defined(CPU_MCXA346VLL) || defined(CPU_MCXA346VLQ) || defined(CPU_MCXA346VPN))
59             .clock_attach_id = kFRO_LF_DIV_to_LPI2C0,
60 #else
61             .clock_attach_id = kFRO12M_to_LPI2C0,
62 #endif
63             .clock_div_name = kCLOCK_DivLPI2C0,
64             .clock_src = kCLOCK_Fro12M,
65             .name = "i2c0",
66         },
67 #endif
68 #ifdef BSP_USING_I2C1
69         {
70             .I2C = LPI2C1,
71             .baud = 100000U,
72 #if (defined(CPU_MCXA346VLH) || defined(CPU_MCXA346VLL) || defined(CPU_MCXA346VLQ) || defined(CPU_MCXA346VPN))
73             .clock_attach_id = kFRO_LF_DIV_to_LPI2C1,
74 #else
75             .clock_attach_id = kFRO12M_to_LPI2C1,
76 #endif
77             .clock_div_name = kCLOCK_DivLPI2C1,
78             .clock_src = kCLOCK_Fro12M,
79             .name = "i2c1",
80         },
81 #endif
82 #ifdef BSP_USING_I2C2
83         {
84             .I2C = LPI2C2,
85             .baud = 100000U,
86 #if (defined(CPU_MCXA346VLH) || defined(CPU_MCXA346VLL) || defined(CPU_MCXA346VLQ) || defined(CPU_MCXA346VPN))
87             .clock_attach_id = kFRO_LF_DIV_to_LPI2C2,
88 #else
89             .clock_attach_id = kFRO12M_to_LPI2C2,
90 #endif
91             .clock_div_name = kCLOCK_DivLPI2C2,
92             .clock_src = kCLOCK_Fro12M,
93             .name = "i2c2",
94         },
95 #endif
96 #ifdef BSP_USING_I2C3
97         {
98             .I2C = LPI2C3,
99             .baud = 100000U,
100 #if (defined(CPU_MCXA346VLH) || defined(CPU_MCXA346VLL) || defined(CPU_MCXA346VLQ) || defined(CPU_MCXA346VPN))
101             .clock_attach_id = kFRO_LF_DIV_to_LPI2C3,
102 #else
103             .clock_attach_id = kFRO12M_to_LPI2C3,
104 #endif
105             .clock_div_name = kCLOCK_DivLPI2C3,
106             .clock_src = kCLOCK_Fro12M,
107             .name = "i2c3",
108         },
109 #endif
110 };
111 
lpc_i2c_xfer(struct rt_i2c_bus_device * bus,struct rt_i2c_msg msgs[],rt_uint32_t num)112 static rt_ssize_t lpc_i2c_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num)
113 {
114     struct rt_i2c_msg *msg;
115     lpi2c_master_transfer_t xfer = {0};
116     rt_uint32_t i;
117     rt_ssize_t ret = 0;
118 
119     struct lpc_i2c_bus *lpc_i2c = (struct lpc_i2c_bus *)bus;
120 
121     for (i = 0; i < num; i++)
122     {
123         msg = &msgs[i];
124 
125         if (msg->flags & RT_I2C_RD)
126         {
127             xfer.slaveAddress = msg->addr;
128             xfer.direction = kLPI2C_Read;
129             xfer.subaddress = 0;
130             xfer.subaddressSize = 0;
131             xfer.data = msg->buf;
132             xfer.dataSize = msg->len;
133             if(i != 0)
134                 xfer.flags = kLPI2C_TransferRepeatedStartFlag;
135             else
136                 xfer.flags = kLPI2C_TransferDefaultFlag;
137 
138             if (LPI2C_MasterTransferBlocking(lpc_i2c->I2C, &xfer) != kStatus_Success)
139             {
140                 LOG_D("i2c bus read failed!\n");
141                 return i;
142             }
143         }
144         else
145         {
146             xfer.slaveAddress = msg->addr;
147             xfer.direction = kLPI2C_Write;
148             xfer.subaddress = 0;
149             xfer.subaddressSize = 0;
150             xfer.data = msg->buf;
151             xfer.dataSize = msg->len;
152             if(i == 0)
153                 xfer.flags = kLPI2C_TransferNoStopFlag;
154             else
155                 xfer.flags = kLPI2C_TransferDefaultFlag;
156 
157             if (LPI2C_MasterTransferBlocking(lpc_i2c->I2C, &xfer) != kStatus_Success)
158             {
159                 LOG_D("i2c bus write failed!\n");
160                 return i;
161             }
162         }
163     }
164     ret = i;
165 
166     return ret;
167 }
168 
169 static const struct rt_i2c_bus_device_ops i2c_ops =
170 {
171     lpc_i2c_xfer,
172     RT_NULL,
173     RT_NULL
174 };
175 
rt_hw_i2c_init(void)176 int rt_hw_i2c_init(void)
177 {
178     int i;
179     lpi2c_master_config_t masterConfig;
180 
181     for(i=0; i<ARRAY_SIZE(lpc_obj); i++)
182     {
183         CLOCK_SetClockDiv(lpc_obj[i].clock_div_name, 1u);
184         CLOCK_AttachClk(lpc_obj[i].clock_attach_id);
185 
186         LPI2C_MasterGetDefaultConfig(&masterConfig);
187         masterConfig.baudRate_Hz = lpc_obj[i].baud;
188 
189         LPI2C_MasterInit(lpc_obj[i].I2C, &masterConfig, CLOCK_GetFreq(lpc_obj[i].clock_src));
190 
191         lpc_obj[i].parent.ops = &i2c_ops;
192 
193         rt_i2c_bus_device_register(&lpc_obj[i].parent, lpc_obj[i].name);
194     }
195 
196     return RT_EOK;
197 }
198 INIT_DEVICE_EXPORT(rt_hw_i2c_init);
199 
200 #endif /* RT_USING_I2C */
201 
202 
203 
204