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 * 2024-06-25 Andeyqi the first version
9 */
10 #include <rtthread.h>
11 #include <rthw.h>
12 #include <rtdevice.h>
13 #include <board.h>
14
15 #ifdef BSP_USING_SW_I2C
16
17 #define LOG_TAG "drv.i2c"
18 #include <rtdbg.h>
19
20 /* MCXNXXX config class */
21 struct mcxnxxx_soft_i2c_config
22 {
23 rt_uint8_t scl;
24 rt_uint8_t sda;
25 const char *bus_name;
26 };
27
28 /* MCXNXXX i2c dirver class */
29 struct mcxnxxx_i2c
30 {
31 struct rt_i2c_bit_ops ops;
32 struct rt_i2c_bus_device i2c2_bus;
33 };
34
35 #if defined(BSP_USING_SW_I2C0)
36 #define SW_I2C0_BUS_CONFIG \
37 { \
38 .scl = BSP_SW_I2C0_SCL_PIN, \
39 .sda = BSP_SW_I2C0_SDA_PIN, \
40 .bus_name = "swi2c0", \
41 }
42 #endif
43
44 static const struct mcxnxxx_soft_i2c_config soft_i2c_config[] =
45 {
46 #if defined(BSP_USING_SW_I2C0)
47 SW_I2C0_BUS_CONFIG,
48 #endif
49 };
50
51 static struct mcxnxxx_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
52
53 /**
54 * @brief This function initializes the i2c pin.
55 * @param i2c
56 * @retval None
57 */
mcxnxxx_i2c_gpio_init(struct mcxnxxx_i2c * i2c)58 static void mcxnxxx_i2c_gpio_init(struct mcxnxxx_i2c *i2c)
59 {
60 struct mcxnxxx_soft_i2c_config* cfg = (struct mcxnxxx_soft_i2c_config*)i2c->ops.data;
61
62 rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD);
63 rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
64
65 rt_pin_write(cfg->scl, PIN_HIGH);
66 rt_pin_write(cfg->sda, PIN_HIGH);
67 }
68
69 /**
70 * @brief This function sets the sda pin.
71 * @param data, state
72 * @retval None
73 */
mcxnxxx_set_sda(void * data,rt_int32_t state)74 static void mcxnxxx_set_sda(void *data, rt_int32_t state)
75 {
76 struct mcxnxxx_soft_i2c_config* cfg = (struct mcxnxxx_soft_i2c_config*)data;
77
78 rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
79
80 if (state)
81 {
82 rt_pin_write(cfg->sda, PIN_HIGH);
83 }
84 else
85 {
86 rt_pin_write(cfg->sda, PIN_LOW);
87 }
88 }
89
90 /**
91 * @brief This function sets the scl pin.
92 * @param data, state
93 * @retval None
94 */
mcxnxxx_set_scl(void * data,rt_int32_t state)95 static void mcxnxxx_set_scl(void *data, rt_int32_t state)
96 {
97 struct mcxnxxx_soft_i2c_config* cfg = (struct mcxnxxx_soft_i2c_config*)data;
98
99 rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD);
100
101 if (state)
102 {
103 rt_pin_write(cfg->scl, PIN_HIGH);
104 }
105 else
106 {
107 rt_pin_write(cfg->scl, PIN_LOW);
108 }
109 }
110
111 /**
112 * @brief This function gets the sda pin state.
113 * @param data
114 * @retval None
115 */
mcxnxxx_get_sda(void * data)116 static rt_int32_t mcxnxxx_get_sda(void *data)
117 {
118 struct mcxnxxx_soft_i2c_config* cfg = (struct mcxnxxx_soft_i2c_config*)data;
119
120 rt_pin_mode(cfg->sda, PIN_MODE_INPUT);
121
122 return rt_pin_read(cfg->sda);
123 }
124
125
126 /**
127 * @brief This function gets the scl pin state.
128 * @param data
129 * @retval None
130 */
mcxnxxx_get_scl(void * data)131 static rt_int32_t mcxnxxx_get_scl(void *data)
132 {
133 struct mcxnxxx_soft_i2c_config* cfg = (struct mcxnxxx_soft_i2c_config*)data;
134
135 rt_pin_mode(cfg->scl,PIN_MODE_INPUT);
136
137 return rt_pin_read(cfg->scl);
138 }
139
140 /**
141 * @brief The time delay function.
142 * @param us
143 * @retval None
144 */
mcxnxxx_udelay(rt_uint32_t us)145 static void mcxnxxx_udelay(rt_uint32_t us)
146 {
147 rt_uint32_t frequency = CLOCK_GetCoreSysClkFreq();
148
149 int i = (frequency/ 4000000 * us);
150 while(i)
151 {
152 i--;
153 }
154 }
155
156 static const struct rt_i2c_bit_ops mcxnxxx_bit_ops_default =
157 {
158 .data = RT_NULL,
159 .set_sda = mcxnxxx_set_sda,
160 .set_scl = mcxnxxx_set_scl,
161 .get_sda = mcxnxxx_get_sda,
162 .get_scl = mcxnxxx_get_scl,
163 .udelay = mcxnxxx_udelay,
164 .delay_us = 1,
165 .timeout = 100
166 };
167
168 /**
169 * @brief if i2c is locked, this function will unlock it
170 * @param cfg
171 * @retval RT_EOK indicates successful unlock.
172 */
mcxnxxx_i2c_bus_unlock(const struct mcxnxxx_soft_i2c_config * cfg)173 static rt_err_t mcxnxxx_i2c_bus_unlock(const struct mcxnxxx_soft_i2c_config *cfg)
174 {
175 rt_int32_t i = 0;
176
177 if (PIN_LOW == rt_pin_read(cfg->sda))
178 {
179 while (i++ < 9)
180 {
181 rt_pin_write(cfg->scl, PIN_HIGH);
182 mcxnxxx_udelay(100);
183 rt_pin_write(cfg->scl, PIN_LOW);
184 mcxnxxx_udelay(100);
185 }
186 }
187 if (PIN_LOW == rt_pin_read(cfg->sda))
188 {
189 return -RT_ERROR;
190 }
191
192 return RT_EOK;
193 }
194
195 /**
196 * @brief I2C initialization function
197 * @param None
198 * @retval RT_EOK indicates successful initialization.
199 */
rt_hw_soft_i2c_init(void)200 int rt_hw_soft_i2c_init(void)
201 {
202 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct mcxnxxx_i2c);
203 rt_err_t result;
204
205 for (int i = 0; i < obj_num; i++)
206 {
207 i2c_obj[i].ops = mcxnxxx_bit_ops_default;
208 i2c_obj[i].ops.data = (void*)&soft_i2c_config[i];
209 i2c_obj[i].i2c2_bus.priv = &i2c_obj[i].ops;
210 mcxnxxx_i2c_gpio_init(&i2c_obj[i]);
211
212 result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c2_bus, soft_i2c_config[i].bus_name);
213
214 RT_ASSERT(result == RT_EOK);
215
216 mcxnxxx_i2c_bus_unlock(&soft_i2c_config[i]);
217
218 LOG_D("software simulation %s init done, pin scl: %d, pin sda %d",
219 soft_i2c_config[i].bus_name,
220 soft_i2c_config[i].scl,
221 soft_i2c_config[i].sda);
222 }
223
224 return RT_EOK;
225 }
226 INIT_APP_EXPORT(rt_hw_soft_i2c_init);
227
228 #endif /* RT_USING_I2C */
229