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