1 /*
2 * Copyright (C) 2022-2024, Xiaohua Semiconductor Co., Ltd.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-04-28 CDT first version
9 */
10
11 /*******************************************************************************
12 * Include files
13 ******************************************************************************/
14 #include "drv_soft_i2c.h"
15 #include "board_config.h"
16
17 #if defined(RT_USING_I2C)
18
19 #if defined(BSP_USING_I2C1_SW) || defined(BSP_USING_I2C2_SW) || defined(BSP_USING_I2C3_SW) || \
20 defined(BSP_USING_I2C4_SW) || defined(BSP_USING_I2C5_SW) || defined(BSP_USING_I2C6_SW)
21
22 /*******************************************************************************
23 * Local type definitions ('typedef')
24 ******************************************************************************/
25
26 /*******************************************************************************
27 * Local pre-processor symbols/macros ('#define')
28 ******************************************************************************/
29 //#define DRV_DEBUG
30 #define LOG_TAG "drv.i2c"
31 #include <drv_log.h>
32
33 /*******************************************************************************
34 * Global variable definitions (declared in header file with 'extern')
35 ******************************************************************************/
36
37 /*******************************************************************************
38 * Local function prototypes ('static')
39 ******************************************************************************/
40
41 /*******************************************************************************
42 * Local variable definitions ('static')
43 ******************************************************************************/
44
45 static const struct hc32_soft_i2c_config soft_i2c_config[] =
46 {
47 #ifdef BSP_USING_I2C1_SW
48 I2C1_BUS_CONFIG,
49 #endif
50 #ifdef BSP_USING_I2C2_SW
51 I2C2_BUS_CONFIG,
52 #endif
53 #ifdef BSP_USING_I2C3_SW
54 I2C3_BUS_CONFIG,
55 #endif
56 #ifdef BSP_USING_I2C4_SW
57 I2C4_BUS_CONFIG,
58 #endif
59 #ifdef BSP_USING_I2C5_SW
60 I2C5_BUS_CONFIG,
61 #endif
62 #ifdef BSP_USING_I2C6_SW
63 I2C6_BUS_CONFIG,
64 #endif
65 };
66
67 static struct hc32_soft_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
68
69 /*******************************************************************************
70 * Function implementation - global ('extern') and local ('static')
71 ******************************************************************************/
72 /**
73 * This function initializes the i2c pin.
74 *
75 * @param Hc32 i2c driver class.
76 */
hc32_i2c_gpio_init(struct hc32_soft_i2c * i2c)77 static void hc32_i2c_gpio_init(struct hc32_soft_i2c *i2c)
78 {
79 struct hc32_soft_i2c_config *cfg = (struct hc32_soft_i2c_config *)i2c->ops.data;
80
81 rt_pin_mode(cfg->scl_pin, PIN_MODE_OUTPUT_OD);
82 rt_pin_mode(cfg->sda_pin, PIN_MODE_OUTPUT_OD);
83 rt_pin_write(cfg->scl_pin, PIN_HIGH);
84 rt_pin_write(cfg->sda_pin, PIN_HIGH);
85 }
86
hc32_i2c_pin_init(void)87 static void hc32_i2c_pin_init(void)
88 {
89 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct hc32_soft_i2c);
90
91 for (rt_size_t i = 0; i < obj_num; i++)
92 {
93 hc32_i2c_gpio_init(&i2c_obj[i]);
94 }
95 }
96
97 /**
98 * This function sets the sda pin.
99 *
100 * @param Hc32 config class.
101 * @param The sda pin state.
102 */
hc32_set_sda(void * data,rt_int32_t state)103 static void hc32_set_sda(void *data, rt_int32_t state)
104 {
105 struct hc32_soft_i2c_config *cfg = (struct hc32_soft_i2c_config *)data;
106
107 if (state)
108 {
109 rt_pin_write(cfg->sda_pin, PIN_HIGH);
110 }
111 else
112 {
113 rt_pin_write(cfg->sda_pin, PIN_LOW);
114 }
115 }
116
117 /**
118 * This function sets the scl pin.
119 *
120 * @param Hc32 config class.
121 * @param The scl pin state.
122 */
hc32_set_scl(void * data,rt_int32_t state)123 static void hc32_set_scl(void *data, rt_int32_t state)
124 {
125 struct hc32_soft_i2c_config *cfg = (struct hc32_soft_i2c_config *)data;
126
127 if (state)
128 {
129 rt_pin_write(cfg->scl_pin, PIN_HIGH);
130 }
131 else
132 {
133 rt_pin_write(cfg->scl_pin, PIN_LOW);
134 }
135 }
136
137 /**
138 * This function gets the sda pin state.
139 *
140 * @param The sda pin state.
141 */
hc32_get_sda(void * data)142 static rt_int32_t hc32_get_sda(void *data)
143 {
144 struct hc32_soft_i2c_config *cfg = (struct hc32_soft_i2c_config *)data;
145 return rt_pin_read(cfg->sda_pin);
146 }
147
148 /**
149 * This function gets the scl pin state.
150 *
151 * @param The scl pin state.
152 */
hc32_get_scl(void * data)153 static rt_int32_t hc32_get_scl(void *data)
154 {
155 struct hc32_soft_i2c_config *cfg = (struct hc32_soft_i2c_config *)data;
156 return rt_pin_read(cfg->scl_pin);
157 }
158
159 /**
160 * The time delay function.
161 *
162 * @param microseconds.
163 */
hc32_udelay(rt_uint32_t us)164 static void hc32_udelay(rt_uint32_t us)
165 {
166 rt_uint32_t ticks;
167 rt_uint32_t told, tnow, tcnt = 0;
168 rt_uint32_t reload = SysTick->LOAD;
169
170 ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
171 told = SysTick->VAL;
172 while (1)
173 {
174 tnow = SysTick->VAL;
175 if (tnow != told)
176 {
177 if (tnow < told)
178 {
179 tcnt += told - tnow;
180 }
181 else
182 {
183 tcnt += reload - tnow + told;
184 }
185 told = tnow;
186 if (tcnt >= ticks)
187 {
188 break;
189 }
190 }
191 }
192 }
193
194 static const struct rt_i2c_bit_ops hc32_bit_ops_default =
195 {
196 .data = RT_NULL,
197 .pin_init = hc32_i2c_pin_init,
198 .set_sda = hc32_set_sda,
199 .set_scl = hc32_set_scl,
200 .get_sda = hc32_get_sda,
201 .get_scl = hc32_get_scl,
202 .udelay = hc32_udelay,
203 .delay_us = 1,
204 .timeout = 100,
205 .i2c_pin_init_flag = RT_FALSE
206 };
207
208 /**
209 * if i2c is locked, this function will unlock it
210 *
211 * @param hc32 config class
212 *
213 * @return RT_EOK indicates successful unlock.
214 */
hc32_i2c_bus_unlock(const struct hc32_soft_i2c_config * cfg)215 static rt_err_t hc32_i2c_bus_unlock(const struct hc32_soft_i2c_config *cfg)
216 {
217 rt_uint32_t i = 0;
218
219 if (PIN_LOW == rt_pin_read(cfg->sda_pin))
220 {
221 while (i++ < 9)
222 {
223 rt_pin_write(cfg->scl_pin, PIN_HIGH);
224 hc32_udelay(100);
225 rt_pin_write(cfg->scl_pin, PIN_LOW);
226 hc32_udelay(100);
227 }
228 }
229 if (PIN_LOW == rt_pin_read(cfg->sda_pin))
230 {
231 return -RT_ERROR;
232 }
233
234 return RT_EOK;
235 }
236
237 /* I2C initialization function */
hc32_soft_i2c_init(void)238 int hc32_soft_i2c_init(void)
239 {
240 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct hc32_soft_i2c);
241 rt_err_t result;
242
243 for (rt_size_t i = 0; i < obj_num; i++)
244 {
245 i2c_obj[i].ops = hc32_bit_ops_default;
246 i2c_obj[i].ops.data = (void *)&soft_i2c_config[i];
247 i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
248
249 result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, soft_i2c_config[i].bus_name);
250 RT_ASSERT(result == RT_EOK);
251 hc32_i2c_bus_unlock(&soft_i2c_config[i]);
252 }
253
254 return RT_EOK;
255 }
256 INIT_BOARD_EXPORT(hc32_soft_i2c_init);
257
258 #endif
259
260 #endif /* RT_USING_I2C */
261
262 /*******************************************************************************
263 * EOF (not truncated)
264 ******************************************************************************/
265