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  * 2022-02-22     airm2m       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 air32_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 air32_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
42 
43 /**
44  * This function initializes the i2c pin.
45  *
46  * @param air32 i2c dirver class.
47  */
air32_i2c_gpio_init(struct air32_i2c * i2c)48 static void air32_i2c_gpio_init(struct air32_i2c *i2c)
49 {
50     struct air32_soft_i2c_config* cfg = (struct air32_soft_i2c_config*)i2c->ops.data;
51 
52     rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD);
53     rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
54 
55     rt_pin_write(cfg->scl, PIN_HIGH);
56     rt_pin_write(cfg->sda, PIN_HIGH);
57 }
58 
air32_i2c_pin_init(void)59 static void air32_i2c_pin_init(void)
60 {
61     rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct air32_i2c);
62 
63     for(rt_size_t i = 0; i < obj_num; i++)
64     {
65         air32_i2c_gpio_init(&i2c_obj[i]);
66     }
67 }
68 
69 /**
70  * This function sets the sda pin.
71  *
72  * @param air32 config class.
73  * @param The sda pin state.
74  */
air32_set_sda(void * data,rt_int32_t state)75 static void air32_set_sda(void *data, rt_int32_t state)
76 {
77     struct air32_soft_i2c_config* cfg = (struct air32_soft_i2c_config*)data;
78     if (state)
79     {
80         rt_pin_write(cfg->sda, PIN_HIGH);
81     }
82     else
83     {
84         rt_pin_write(cfg->sda, PIN_LOW);
85     }
86 }
87 
88 /**
89  * This function sets the scl pin.
90  *
91  * @param air32 config class.
92  * @param The scl pin state.
93  */
air32_set_scl(void * data,rt_int32_t state)94 static void air32_set_scl(void *data, rt_int32_t state)
95 {
96     struct air32_soft_i2c_config* cfg = (struct air32_soft_i2c_config*)data;
97     if (state)
98     {
99         rt_pin_write(cfg->scl, PIN_HIGH);
100     }
101     else
102     {
103         rt_pin_write(cfg->scl, PIN_LOW);
104     }
105 }
106 
107 /**
108  * This function gets the sda pin state.
109  *
110  * @param The sda pin state.
111  */
air32_get_sda(void * data)112 static rt_int32_t air32_get_sda(void *data)
113 {
114     struct air32_soft_i2c_config* cfg = (struct air32_soft_i2c_config*)data;
115     return rt_pin_read(cfg->sda);
116 }
117 
118 /**
119  * This function gets the scl pin state.
120  *
121  * @param The scl pin state.
122  */
air32_get_scl(void * data)123 static rt_int32_t air32_get_scl(void *data)
124 {
125     struct air32_soft_i2c_config* cfg = (struct air32_soft_i2c_config*)data;
126     return rt_pin_read(cfg->scl);
127 }
128 /**
129  * The time delay function.
130  *
131  * @param microseconds.
132  */
air32_udelay(rt_uint32_t us)133 static void air32_udelay(rt_uint32_t us)
134 {
135     rt_uint32_t ticks;
136     rt_uint32_t told, tnow, tcnt = 0;
137     rt_uint32_t reload = SysTick->LOAD;
138 
139     ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
140     told = SysTick->VAL;
141     while (1)
142     {
143         tnow = SysTick->VAL;
144         if (tnow != told)
145         {
146             if (tnow < told)
147             {
148                 tcnt += told - tnow;
149             }
150             else
151             {
152                 tcnt += reload - tnow + told;
153             }
154             told = tnow;
155             if (tcnt >= ticks)
156             {
157                 break;
158             }
159         }
160     }
161 }
162 
163 static const struct rt_i2c_bit_ops air32_bit_ops_default =
164 {
165     .data     = RT_NULL,
166     .pin_init = air32_i2c_pin_init,
167     .set_sda  = air32_set_sda,
168     .set_scl  = air32_set_scl,
169     .get_sda  = air32_get_sda,
170     .get_scl  = air32_get_scl,
171     .udelay   = air32_udelay,
172     .delay_us = 1,
173     .timeout  = 100,
174     .i2c_pin_init_flag = RT_FALSE
175 };
176 
177 /**
178  * if i2c is locked, this function will unlock it
179  *
180  * @param air32 config class
181  *
182  * @return RT_EOK indicates successful unlock.
183  */
air32_i2c_bus_unlock(const struct air32_soft_i2c_config * cfg)184 static rt_err_t air32_i2c_bus_unlock(const struct air32_soft_i2c_config *cfg)
185 {
186     rt_int32_t i = 0;
187 
188     if (PIN_LOW == rt_pin_read(cfg->sda))
189     {
190         while (i++ < 9)
191         {
192             rt_pin_write(cfg->scl, PIN_HIGH);
193             air32_udelay(100);
194             rt_pin_write(cfg->scl, PIN_LOW);
195             air32_udelay(100);
196         }
197     }
198     if (PIN_LOW == rt_pin_read(cfg->sda))
199     {
200         return -RT_ERROR;
201     }
202 
203     return RT_EOK;
204 }
205 
206 /* I2C initialization function */
rt_sw_i2c_init(void)207 int rt_sw_i2c_init(void)
208 {
209     rt_err_t result;
210 
211     for (rt_size_t i = 0; i < sizeof(i2c_obj) / sizeof(struct air32_i2c); i++)
212     {
213         i2c_obj[i].ops = air32_bit_ops_default;
214         i2c_obj[i].ops.data = (void*)&soft_i2c_config[i];
215         i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
216 
217         result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, soft_i2c_config[i].bus_name);
218         RT_ASSERT(result == RT_EOK);
219         air32_i2c_bus_unlock(&soft_i2c_config[i]);
220 
221         LOG_D("software simulation %s init done, pin scl: %d, pin sda %d",
222         soft_i2c_config[i].bus_name,
223         soft_i2c_config[i].scl,
224         soft_i2c_config[i].sda);
225     }
226 
227     return RT_EOK;
228 }
229 INIT_BOARD_EXPORT(rt_sw_i2c_init);
230 
231 #endif /* RT_USING_I2C */
232