1 /*
2 * Copyright (c) 2020-2021, Bluetrum Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2021-01-07 greedyhao first version
9 */
10
11 #include <board.h>
12 #include "drv_soft_i2c.h"
13
14 #ifdef RT_USING_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) && !defined(BSP_USING_I2C3) && !defined(BSP_USING_I2C4)
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 ab32_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 #ifdef BSP_USING_I2C3
34 I2C3_BUS_CONFIG,
35 #endif
36 #ifdef BSP_USING_I2C4
37 I2C4_BUS_CONFIG,
38 #endif
39 };
40
41 static struct ab32_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])] = {0};
42
43 /**
44 * This function initializes the i2c pin.
45 *
46 * @param ab32 i2c dirver class.
47 */
ab32_i2c_gpio_init(struct ab32_i2c * i2c)48 static void ab32_i2c_gpio_init(struct ab32_i2c *i2c)
49 {
50 struct ab32_soft_i2c_config* cfg = (struct ab32_soft_i2c_config*)i2c->ops.data;
51
52 cfg->scl_mode = PIN_MODE_OUTPUT_OD;
53 cfg->sda_mode = PIN_MODE_OUTPUT_OD;
54 rt_pin_mode(cfg->scl, cfg->scl_mode);
55 rt_pin_mode(cfg->sda, cfg->sda_mode);
56
57 rt_pin_write(cfg->scl, PIN_HIGH);
58 rt_pin_write(cfg->sda, PIN_HIGH);
59 }
60
ab32_i2c_pin_init(void)61 static void ab32_i2c_pin_init(void)
62 {
63 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct ab32_i2c);
64
65 for(rt_size_t i = 0; i < obj_num; i++)
66 {
67 ab32_i2c_gpio_init(&i2c_obj[i]);
68 }
69 }
70
71 /**
72 * This function sets the sda pin.
73 *
74 * @param data ab32 config class.
75 * @param state The sda pin state.
76 */
ab32_set_sda(void * data,rt_int32_t state)77 static void ab32_set_sda(void *data, rt_int32_t state)
78 {
79 struct ab32_soft_i2c_config* cfg = (struct ab32_soft_i2c_config*)data;
80
81 if (cfg->sda_mode == PIN_MODE_INPUT_PULLUP) {
82 cfg->sda_mode = PIN_MODE_OUTPUT_OD;
83 rt_pin_mode(cfg->sda, cfg->sda_mode);
84 }
85
86 if (state)
87 {
88 rt_pin_write(cfg->sda, PIN_HIGH);
89 }
90 else
91 {
92 rt_pin_write(cfg->sda, PIN_LOW);
93 }
94 }
95
96 /**
97 * This function sets the scl pin.
98 *
99 * @param data ab32 config class.
100 * @param state The scl pin state.
101 */
ab32_set_scl(void * data,rt_int32_t state)102 static void ab32_set_scl(void *data, rt_int32_t state)
103 {
104 struct ab32_soft_i2c_config* cfg = (struct ab32_soft_i2c_config*)data;
105
106 if (cfg->scl_mode == PIN_MODE_INPUT_PULLUP) {
107 cfg->scl_mode = PIN_MODE_OUTPUT_OD;
108 rt_pin_mode(cfg->scl, cfg->scl_mode);
109 }
110
111 if (state)
112 {
113 rt_pin_write(cfg->scl, PIN_HIGH);
114 }
115 else
116 {
117 rt_pin_write(cfg->scl, PIN_LOW);
118 }
119 }
120
121 /**
122 * This function gets the sda pin state.
123 *
124 * @param data The sda pin state.
125 */
ab32_get_sda(void * data)126 static rt_int32_t ab32_get_sda(void *data)
127 {
128 struct ab32_soft_i2c_config* cfg = (struct ab32_soft_i2c_config*)data;
129
130 if (cfg->sda_mode != PIN_MODE_INPUT_PULLUP) {
131 cfg->sda_mode = PIN_MODE_INPUT_PULLUP;
132 rt_pin_mode(cfg->sda, cfg->sda_mode);
133 }
134
135 return rt_pin_read(cfg->sda);
136 }
137
138 /**
139 * This function gets the scl pin state.
140 *
141 * @param data The scl pin state.
142 */
ab32_get_scl(void * data)143 static rt_int32_t ab32_get_scl(void *data)
144 {
145 struct ab32_soft_i2c_config* cfg = (struct ab32_soft_i2c_config*)data;
146
147 if (cfg->scl_mode == PIN_MODE_INPUT_PULLUP) {
148 cfg->scl_mode = PIN_MODE_INPUT_PULLUP;
149 rt_pin_mode(cfg->scl, cfg->scl_mode);
150 }
151
152 return rt_pin_read(cfg->scl);
153 }
154
155 static const struct rt_i2c_bit_ops ab32_bit_ops_default =
156 {
157 .data = RT_NULL,
158 .pin_init = ab32_i2c_pin_init,
159 .set_sda = ab32_set_sda,
160 .set_scl = ab32_set_scl,
161 .get_sda = ab32_get_sda,
162 .get_scl = ab32_get_scl,
163 .udelay = rt_hw_us_delay,
164 .delay_us = 1,
165 .timeout = 100,
166 .i2c_pin_init_flag = RT_FALSE
167 };
168
169 /**
170 * if i2c is locked, this function will unlock it
171 *
172 * @param cfg ab32 config class
173 *
174 * @return RT_EOK indicates successful unlock.
175 */
ab32_i2c_bus_unlock(const struct ab32_soft_i2c_config * cfg)176 static rt_err_t ab32_i2c_bus_unlock(const struct ab32_soft_i2c_config *cfg)
177 {
178 rt_int32_t i = 0;
179
180 if (PIN_LOW == rt_pin_read(cfg->sda))
181 {
182 while (i++ < 9)
183 {
184 rt_pin_write(cfg->scl, PIN_HIGH);
185 rt_hw_us_delay(100);
186 rt_pin_write(cfg->scl, PIN_LOW);
187 rt_hw_us_delay(100);
188 }
189 }
190 if (PIN_LOW == rt_pin_read(cfg->sda))
191 {
192 return -RT_ERROR;
193 }
194
195 return RT_EOK;
196 }
197
198 /* I2C initialization function */
rt_hw_i2c_init(void)199 int rt_hw_i2c_init(void)
200 {
201 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct ab32_i2c);
202 rt_err_t result;
203
204 for (rt_size_t i = 0; i < obj_num; i++)
205 {
206 i2c_obj[i].ops = ab32_bit_ops_default;
207 i2c_obj[i].ops.data = (void*)&soft_i2c_config[i];
208 i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
209
210 result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, soft_i2c_config[i].bus_name);
211 RT_ASSERT(result == RT_EOK);
212 ab32_i2c_bus_unlock(&soft_i2c_config[i]);
213
214 LOG_D("software simulation %s init done, pin scl: %d, pin sda %d",
215 soft_i2c_config[i].bus_name,
216 soft_i2c_config[i].scl,
217 soft_i2c_config[i].sda);
218 }
219
220 return RT_EOK;
221 }
222 INIT_BOARD_EXPORT(rt_hw_i2c_init);
223
224 #endif
225