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 * 2022-09-19 hg0720 the first version which add from wch
9 */
10
11 #include <board.h>
12 #include "drv_soft_i2c.h"
13
14 #ifdef BSP_USING_SOFT_I2C
15
16 //#define DRV_DEBUG
17 #define LOG_TAG "drv.i2c"
18 #include <drv_log.h>
19
20 #if !defined(BSP_USING_I2C1) && !defined(BSP_USING_I2C2)
21 #error "Please define at least one BSP_USING_I2Cx"
22 /* this driver can be disabled at menuconfig -> RT-Thread Components -> Device Drivers */
23 #endif
24
25 static const struct ch32_soft_i2c_config soft_i2c_config[] =
26 {
27 #ifdef BSP_USING_I2C1
28 I2C1_BUS_CONFIG,
29 #endif
30 #ifdef BSP_USING_I2C2
31 I2C2_BUS_CONFIG,
32 #endif
33 };
34
35 static struct ch32_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
36
37 /*
38 * This function initializes the i2c pin.
39 *
40 * @param ch32 i2c dirver class.
41 */
ch32_i2c_gpio_init(struct ch32_i2c * i2c)42 static void ch32_i2c_gpio_init(struct ch32_i2c *i2c)
43 {
44 struct ch32_soft_i2c_config* cfg = (struct ch32_soft_i2c_config*)i2c->ops.data;
45
46 rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD);
47 rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
48
49 rt_pin_write(cfg->scl, PIN_HIGH);
50 rt_pin_write(cfg->sda, PIN_HIGH);
51 }
52
ch32_i2c_pin_init(void)53 static void ch32_i2c_pin_init(void)
54 {
55 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct ch32_i2c);
56
57 for(rt_size_t i = 0; i < obj_num; i++)
58 {
59 ch32_i2c_gpio_init(&i2c_obj[i]);
60 }
61 }
62
63 /*
64 * This function sets the sda pin.
65 *
66 * @param Ch32 config class.
67 * @param The sda pin state.
68 */
ch32_set_sda(void * data,rt_int32_t state)69 static void ch32_set_sda(void *data, rt_int32_t state)
70 {
71 struct ch32_soft_i2c_config* cfg = (struct ch32_soft_i2c_config*)data;
72 if (state)
73 {
74 rt_pin_write(cfg->sda, PIN_HIGH);
75 }
76 else
77 {
78 rt_pin_write(cfg->sda, PIN_LOW);
79 }
80 }
81
82 /*
83 * This function sets the scl pin.
84 *
85 * @param Ch32 config class.
86 * @param The scl pin state.
87 */
ch32_set_scl(void * data,rt_int32_t state)88 static void ch32_set_scl(void *data, rt_int32_t state)
89 {
90 struct ch32_soft_i2c_config* cfg = (struct ch32_soft_i2c_config*)data;
91 if (state)
92 {
93 rt_pin_write(cfg->scl, PIN_HIGH);
94 }
95 else
96 {
97 rt_pin_write(cfg->scl, PIN_LOW);
98 }
99 }
100
101 /*
102 * This function gets the sda pin state.
103 *
104 * @param The sda pin state.
105 */
ch32_get_sda(void * data)106 static rt_int32_t ch32_get_sda(void *data)
107 {
108 struct ch32_soft_i2c_config* cfg = (struct ch32_soft_i2c_config*)data;
109 return rt_pin_read(cfg->sda);
110 }
111
112 /*
113 * This function gets the scl pin state.
114 *
115 * @param The scl pin state.
116 */
ch32_get_scl(void * data)117 static rt_int32_t ch32_get_scl(void *data)
118 {
119 struct ch32_soft_i2c_config* cfg = (struct ch32_soft_i2c_config*)data;
120 return rt_pin_read(cfg->scl);
121 }
122
123 /*
124 * The time delay function.
125 *
126 * @param microseconds.
127 */
ch32_udelay(rt_uint32_t us)128 static void ch32_udelay(rt_uint32_t us)
129 {
130 rt_uint32_t ticks;
131 rt_uint32_t told, tnow, tcnt = 0;
132 rt_uint32_t reload = SysTick->CMP;
133
134 ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
135 told = SysTick->CNT;
136 while (1)
137 {
138 tnow = SysTick->CNT;
139 if (tnow != told)
140 {
141 if (tnow > told)
142 {
143 tcnt += tnow - told;
144 }
145 else
146 {
147 tcnt += reload - told + tnow;
148 }
149 told = tnow;
150 if (tcnt >= ticks)
151 {
152 break;
153 }
154 }
155 }
156 }
157
158 static const struct rt_i2c_bit_ops ch32_bit_ops_default =
159 {
160 .data = RT_NULL,
161 .pin_init = ch32_i2c_pin_init,
162 .set_sda = ch32_set_sda,
163 .set_scl = ch32_set_scl,
164 .get_sda = ch32_get_sda,
165 .get_scl = ch32_get_scl,
166 .udelay = ch32_udelay,
167 .delay_us = 1,
168 .timeout = 100,
169 .i2c_pin_init_flag = RT_FALSE
170 };
171
172 /*
173 * if i2c is locked, this function will unlock it
174 *
175 * @param ch32 config class
176 *
177 * @return RT_EOK indicates successful unlock.
178 */
ch32_i2c_bus_unlock(const struct ch32_soft_i2c_config * cfg)179 static rt_err_t ch32_i2c_bus_unlock(const struct ch32_soft_i2c_config *cfg)
180 {
181 rt_int32_t i = 0;
182
183 if (PIN_LOW == rt_pin_read(cfg->sda))
184 {
185 while (i++ < 9)
186 {
187 rt_pin_write(cfg->scl, PIN_HIGH);
188 ch32_udelay(100);
189 rt_pin_write(cfg->scl, PIN_LOW);
190 ch32_udelay(100);
191 }
192 }
193 if (PIN_LOW == rt_pin_read(cfg->sda))
194 {
195 return -RT_ERROR;
196 }
197
198 return RT_EOK;
199 }
200
201 /* I2C initialization function */
rt_hw_i2c_init(void)202 int rt_hw_i2c_init(void)
203 {
204 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct ch32_i2c);
205 rt_err_t result;
206
207 for (rt_size_t i = 0; i < obj_num; i++)
208 {
209 i2c_obj[i].ops = ch32_bit_ops_default;
210 i2c_obj[i].ops.data = (void*)&soft_i2c_config[i];
211 i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
212
213 result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, soft_i2c_config[i].bus_name);
214 RT_ASSERT(result == RT_EOK);
215 ch32_i2c_bus_unlock(&soft_i2c_config[i]);
216 LOG_D("software simulation %s init done, pin scl: %d, pin sda %d",
217 soft_i2c_config[i].bus_name,
218 soft_i2c_config[i].scl,
219 soft_i2c_config[i].sda);
220 }
221
222 return RT_EOK;
223 }
224 INIT_BOARD_EXPORT(rt_hw_i2c_init);
225
226 #endif /* RT_USING_I2C */
227