1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2019-03-22 balanceTWK first version
9 */
10
11 #include <board.h>
12 #include "drv_soft_i2c.h"
13
14 #include "wm_regs.h"
15 #include "wm_gpio.h"
16 #include "pin_map.h"
17
18 #define DBG_SECTION_NAME "soft_i2c"
19 #define DBG_COLOR
20 #define DBG_LEVEL DBG_LOG
21 #include <rtdbg.h>
22
23 #ifdef BSP_USING_SOFT_I2C
24
25 #if !defined(BSP_USING_SOFT_I2C1) && !defined(BSP_USING_SOFT_I2C2) && !defined(BSP_USING_SOFT_I2C3)
26 #error "Please define at least one BSP_USING_SOFT_I2Cx"
27 #endif
28
29 static const struct w60x_soft_i2c_config soft_i2c_config[] =
30 {
31 #ifdef BSP_USING_SOFT_I2C1
32 I2C1_BUS_CONFIG,
33 #endif
34 #ifdef BSP_USING_SOFT_I2C2
35 I2C2_BUS_CONFIG,
36 #endif
37 #ifdef BSP_USING_SOFT_I2C3
38 I2C3_BUS_CONFIG,
39 #endif
40 };
41
42 static struct w60x_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
43
44 /**
45 * This function initializes the i2c pin.
46 *
47 * @param w60x i2c dirver class.
48 */
w60x_i2c_gpio_init(struct w60x_i2c * i2c)49 static void w60x_i2c_gpio_init(struct w60x_i2c *i2c)
50 {
51 struct w60x_soft_i2c_config* cfg = (struct w60x_soft_i2c_config*)i2c->ops.data;
52 rt_int16_t scl,sda;
53
54 scl = wm_get_pin(cfg->scl);
55 sda = wm_get_pin(cfg->sda);
56
57 tls_gpio_cfg((enum tls_io_name)scl, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
58 tls_gpio_cfg((enum tls_io_name)sda, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
59
60 tls_gpio_write((enum tls_io_name)scl, 1);
61 tls_gpio_write((enum tls_io_name)sda, 1);
62 }
63
w60x_i2c_pin_init(void)64 static void w60x_i2c_pin_init(void)
65 {
66 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct w60x_i2c);
67
68 for(rt_size_t i = 0; i < obj_num; i++)
69 {
70 w60x_i2c_gpio_init(&i2c_obj[i]);
71 }
72 }
73
74 /**
75 * This function sets the sda pin.
76 *
77 * @param w60x config class.
78 * @param The sda pin state.
79 */
w60x_set_sda(void * data,rt_int32_t state)80 static void w60x_set_sda(void *data, rt_int32_t state)
81 {
82 struct w60x_soft_i2c_config* cfg = (struct w60x_soft_i2c_config*)data;
83 rt_int16_t sda;
84
85 sda = wm_get_pin(cfg->sda);
86
87 if (state)
88 {
89 tls_gpio_cfg((enum tls_io_name)sda, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_PULLHIGH);
90 }
91 else
92 {
93 tls_gpio_cfg((enum tls_io_name)sda, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_FLOATING);
94 tls_gpio_write((enum tls_io_name)sda, 0);
95 }
96 }
97
98 /**
99 * This function sets the scl pin.
100 *
101 * @param w60x config class.
102 * @param The scl pin state.
103 */
w60x_set_scl(void * data,rt_int32_t state)104 static void w60x_set_scl(void *data, rt_int32_t state)
105 {
106 struct w60x_soft_i2c_config* cfg = (struct w60x_soft_i2c_config*)data;
107 rt_int16_t scl;
108
109 scl = wm_get_pin(cfg->scl);
110
111 if (state)
112 {
113 tls_gpio_cfg((enum tls_io_name)scl, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_PULLHIGH);
114 }
115 else
116 {
117 tls_gpio_cfg((enum tls_io_name)scl, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_FLOATING);
118 tls_gpio_write((enum tls_io_name)scl, 0);
119 }
120 }
121
122 /**
123 * This function gets the sda pin state.
124 *
125 * @param The sda pin state.
126 */
w60x_get_sda(void * data)127 static rt_int32_t w60x_get_sda(void *data)
128 {
129 struct w60x_soft_i2c_config* cfg = (struct w60x_soft_i2c_config*)data;
130 rt_int16_t sda;
131
132 sda = wm_get_pin(cfg->sda);
133
134 return tls_gpio_read((enum tls_io_name)sda);
135 }
136
137 /**
138 * This function gets the scl pin state.
139 *
140 * @param The scl pin state.
141 */
w60x_get_scl(void * data)142 static rt_int32_t w60x_get_scl(void *data)
143 {
144 struct w60x_soft_i2c_config* cfg = (struct w60x_soft_i2c_config*)data;
145 rt_int16_t scl;
146
147 scl = wm_get_pin(cfg->scl);
148
149 return tls_gpio_read((enum tls_io_name)scl);
150 }
151
152
153 static const struct rt_i2c_bit_ops w60x_bit_ops_default =
154 {
155 .data = RT_NULL,
156 .pin_init = w60x_i2c_pin_init,
157 .set_sda = w60x_set_sda,
158 .set_scl = w60x_set_scl,
159 .get_sda = w60x_get_sda,
160 .get_scl = w60x_get_scl,
161 .udelay = rt_hw_us_delay,
162 .delay_us = 1,
163 .timeout = 100,
164 .i2c_pin_init_flag = RT_FALSE
165 };
166
167 /**
168 * if i2c is locked, this function will unlock it
169 *
170 * @param w60x config class
171 *
172 * @return RT_EOK indicates successful unlock.
173 */
w60x_i2c_bus_unlock(const struct w60x_soft_i2c_config * cfg)174 static rt_err_t w60x_i2c_bus_unlock(const struct w60x_soft_i2c_config *cfg)
175 {
176 rt_int32_t i = 0;
177
178 if (PIN_LOW == rt_pin_read(cfg->sda))
179 {
180 while (i++ < 9)
181 {
182 rt_pin_write(cfg->scl, PIN_HIGH);
183 rt_hw_us_delay(100);
184 rt_pin_write(cfg->scl, PIN_LOW);
185 rt_hw_us_delay(100);
186 }
187 }
188 if (PIN_LOW == rt_pin_read(cfg->sda))
189 {
190 return -RT_ERROR;
191 }
192
193 return RT_EOK;
194 }
195
196 /* I2C initialization function */
rt_soft_i2c_init(void)197 int rt_soft_i2c_init(void)
198 {
199 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct w60x_i2c);
200 rt_err_t result;
201
202 for (rt_size_t i = 0; i < obj_num; i++)
203 {
204 i2c_obj[i].ops = w60x_bit_ops_default;
205 i2c_obj[i].ops.data = (void*)&soft_i2c_config[i];
206 i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
207
208 result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, soft_i2c_config[i].bus_name);
209 RT_ASSERT(result == RT_EOK);
210 w60x_i2c_bus_unlock(&soft_i2c_config[i]);
211
212 LOG_D("software simulation %s init done, pin scl: %d, pin sda %d",
213 soft_i2c_config[i].bus_name,
214 soft_i2c_config[i].scl,
215 soft_i2c_config[i].sda);
216 }
217
218 return RT_EOK;
219 }
220 INIT_DEVICE_EXPORT(rt_soft_i2c_init);
221
222 #endif /* BSP_USING_SOFT_I2C */
223