1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2021-12-20 BruceOu the first version
9 */
10 #include "drv_soft_i2c.h"
11
12 #ifdef RT_USING_I2C
13
14 #define LOG_TAG "drv.i2c"
15 #include <rtdbg.h>
16
17 #if !defined(BSP_USING_I2C0) && !defined(BSP_USING_I2C1) && !defined(BSP_USING_I2C2) && !defined(BSP_USING_I2C3)
18 #error "Please define at least one BSP_USING_I2Cx"
19 /* this driver can be disabled at menuconfig → RT-Thread Components → Device Drivers */
20 #endif
21
22 static const struct gd32_soft_i2c_config soft_i2c_config[] =
23 {
24 #ifdef BSP_USING_I2C0
25 I2C0_BUS_CONFIG,
26 #endif
27 #ifdef BSP_USING_I2C1
28 I2C1_BUS_CONFIG,
29 #endif
30 #ifdef BSP_USING_I2C2
31 I2C2_BUS_CONFIG,
32 #endif
33 #ifdef BSP_USING_I2C3
34 I2C3_BUS_CONFIG,
35 #endif
36 };
37
38 static struct gd32_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
39
40 /**
41 * @brief This function initializes the i2c pin.
42 * @param i2c
43 * @retval None
44 */
gd32_i2c_gpio_init(struct gd32_i2c * i2c)45 static void gd32_i2c_gpio_init(struct gd32_i2c *i2c)
46 {
47 struct gd32_soft_i2c_config* cfg = (struct gd32_soft_i2c_config*)i2c->ops.data;
48
49 rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD);
50 rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
51
52 rt_pin_write(cfg->scl, PIN_HIGH);
53 rt_pin_write(cfg->sda, PIN_HIGH);
54 }
55
gd32_i2c_pin_init(void)56 static void gd32_i2c_pin_init(void)
57 {
58 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct gd32_i2c);
59
60 for(rt_size_t i = 0; i < obj_num; i++)
61 {
62 gd32_i2c_gpio_init(&i2c_obj[i]);
63 }
64 }
65
66 /**
67 * @brief This function sets the sda pin.
68 * @param data, state
69 * @retval None
70 */
gd32_set_sda(void * data,rt_int32_t state)71 static void gd32_set_sda(void *data, rt_int32_t state)
72 {
73 struct gd32_soft_i2c_config* cfg = (struct gd32_soft_i2c_config*)data;
74 if (state)
75 {
76 rt_pin_write(cfg->sda, PIN_HIGH);
77 }
78 else
79 {
80 rt_pin_write(cfg->sda, PIN_LOW);
81 }
82 }
83
84 /**
85 * @brief This function sets the scl pin.
86 * @param data, state
87 * @retval None
88 */
gd32_set_scl(void * data,rt_int32_t state)89 static void gd32_set_scl(void *data, rt_int32_t state)
90 {
91 struct gd32_soft_i2c_config* cfg = (struct gd32_soft_i2c_config*)data;
92 if (state)
93 {
94 rt_pin_write(cfg->scl, PIN_HIGH);
95 }
96 else
97 {
98 rt_pin_write(cfg->scl, PIN_LOW);
99 }
100 }
101
102 /**
103 * @brief This function gets the sda pin state.
104 * @param data
105 * @retval None
106 */
gd32_get_sda(void * data)107 static rt_int32_t gd32_get_sda(void *data)
108 {
109 struct gd32_soft_i2c_config* cfg = (struct gd32_soft_i2c_config*)data;
110 return rt_pin_read(cfg->sda);
111 }
112
113
114 /**
115 * @brief This function gets the scl pin state.
116 * @param data
117 * @retval None
118 */
gd32_get_scl(void * data)119 static rt_int32_t gd32_get_scl(void *data)
120 {
121 struct gd32_soft_i2c_config* cfg = (struct gd32_soft_i2c_config*)data;
122 return rt_pin_read(cfg->scl);
123 }
124
125 /**
126 * @brief The time delay function.
127 * @param us
128 * @retval None
129 */
gd32_udelay(rt_uint32_t us)130 static void gd32_udelay(rt_uint32_t us)
131 {
132 int i = ( rcu_clock_freq_get(CK_SYS) / 4000000 * us);
133 while(i)
134 {
135 i--;
136 }
137 }
138
139 static const struct rt_i2c_bit_ops gd32_bit_ops_default =
140 {
141 .data = RT_NULL,
142 .pin_init = gd32_i2c_pin_init,
143 .set_sda = gd32_set_sda,
144 .set_scl = gd32_set_scl,
145 .get_sda = gd32_get_sda,
146 .get_scl = gd32_get_scl,
147 .udelay = gd32_udelay,
148 .delay_us = 1,
149 .timeout = 100,
150 .i2c_pin_init_flag = RT_FALSE
151 };
152
153 /**
154 * @brief if i2c is locked, this function will unlock it
155 * @param cfg
156 * @retval RT_EOK indicates successful unlock.
157 */
gd32_i2c_bus_unlock(const struct gd32_soft_i2c_config * cfg)158 static rt_err_t gd32_i2c_bus_unlock(const struct gd32_soft_i2c_config *cfg)
159 {
160 rt_int32_t i = 0;
161
162 if (PIN_LOW == rt_pin_read(cfg->sda))
163 {
164 while (i++ < 9)
165 {
166 rt_pin_write(cfg->scl, PIN_HIGH);
167 gd32_udelay(100);
168 rt_pin_write(cfg->scl, PIN_LOW);
169 gd32_udelay(100);
170 }
171 }
172 if (PIN_LOW == rt_pin_read(cfg->sda))
173 {
174 return -RT_ERROR;
175 }
176
177 return RT_EOK;
178 }
179
180 /**
181 * @brief I2C initialization function
182 * @param None
183 * @retval RT_EOK indicates successful initialization.
184 */
rt_hw_i2c_init(void)185 int rt_hw_i2c_init(void)
186 {
187 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct gd32_i2c);
188 rt_err_t result;
189
190 for (rt_size_t i = 0; i < obj_num; i++)
191 {
192 i2c_obj[i].ops = gd32_bit_ops_default;
193 i2c_obj[i].ops.data = (void*)&soft_i2c_config[i];
194 i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
195
196 result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, soft_i2c_config[i].bus_name);
197
198 RT_ASSERT(result == RT_EOK);
199
200 gd32_i2c_bus_unlock(&soft_i2c_config[i]);
201
202 LOG_D("software simulation %s init done, pin scl: %d, pin sda %d",
203 soft_i2c_config[i].bus_name,
204 soft_i2c_config[i].scl,
205 soft_i2c_config[i].sda);
206 }
207
208 return RT_EOK;
209 }
210 INIT_BOARD_EXPORT(rt_hw_i2c_init);
211
212 #endif /* RT_USING_I2C */
213