1 /*
2  * Copyright (c) 2006-2022, Synwit Technology Co.,Ltd.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2018-05-31     ZYH          first version
9  * 2018-12-10     Zohar_Lee    format file
10  * 2020-07-10     lik          rewrite
11  */
12 
13 #include "drv_soft_i2c.h"
14 
15 #ifdef RT_USING_I2C
16 #ifdef BSP_USING_I2C
17 
18 /***************************************************************
19 *!!!!!!!!!!!!!!!!!!!!!!!!!!!!NOTICE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
20 *In order to use swm drv_soft_i2c,you need to commented out
21 line 114 (SDA_H(ops);) and line 167 (SDA_H(ops);) in i2c-bit-ops.c
22 At the same time, add one line (SDA_L(ops);)after line 154 (SCL_L(ops);)
23 in i2c-bit-ops.c
24 ***************************************************************/
25 
26 //#define DRV_DEBUG
27 #define LOG_TAG "drv.i2c"
28 #include <drv_log.h>
29 
30 #if !defined(BSP_USING_I2C0) && !defined(BSP_USING_I2C1)
31 #error "Please define at least one BSP_USING_I2Cx"
32 /* this driver can be disabled at menuconfig ? RT-Thread Components ? Device Drivers */
33 #endif
34 
35 #ifdef BSP_USING_I2C0
36 #define I2C0_BUS_CFG             \
37     {                            \
38         .scl = BSP_I2C0_SCL_PIN, \
39         .sda = BSP_I2C0_SDA_PIN, \
40         .name = "i2c0",          \
41     }
42 #endif
43 
44 #ifdef BSP_USING_I2C1
45 #define I2C1_BUS_CFG             \
46     {                            \
47         .scl = BSP_I2C1_SCL_PIN, \
48         .sda = BSP_I2C1_SDA_PIN, \
49         .name = "i2c1",          \
50     }
51 #endif
52 
53 /* swm config class */
54 struct swm_soft_i2c_cfg
55 {
56     rt_uint8_t scl;
57     rt_uint8_t sda;
58     const char *name;
59 };
60 /* swm i2c dirver class */
61 struct swm_soft_i2c_device
62 {
63     struct rt_i2c_bit_ops ops;
64     struct rt_i2c_bus_device i2c_bus;
65 };
66 static const struct swm_soft_i2c_cfg swm_soft_i2c_cfg[] =
67     {
68 #ifdef BSP_USING_I2C0
69         I2C0_BUS_CFG,
70 #endif
71 #ifdef BSP_USING_I2C1
72         I2C1_BUS_CFG,
73 #endif
74 };
75 
76 static struct swm_soft_i2c_device i2c_obj[sizeof(swm_soft_i2c_cfg) / sizeof(swm_soft_i2c_cfg[0])];
77 
78 /**
79  * This function initializes the i2c pin.
80  *
81  * @param swm i2c dirver class.
82  */
swm_i2c_gpio_init(struct swm_soft_i2c_device * i2c)83 static void swm_i2c_gpio_init(struct swm_soft_i2c_device *i2c)
84 {
85     struct swm_soft_i2c_cfg *soft_i2c_cfg = (struct swm_soft_i2c_cfg *)i2c->ops.data;
86 
87     rt_pin_mode(soft_i2c_cfg->scl, PIN_MODE_OUTPUT_OD);
88     rt_pin_mode(soft_i2c_cfg->sda, PIN_MODE_OUTPUT_OD);
89 
90     rt_pin_write(soft_i2c_cfg->scl, PIN_HIGH);
91     rt_pin_write(soft_i2c_cfg->sda, PIN_HIGH);
92 }
93 
swm_i2c_pin_init(void)94 static void swm_i2c_pin_init(void)
95 {
96     rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct swm_soft_i2c_device);
97 
98     for(rt_size_t i = 0; i < obj_num; i++)
99     {
100         swm_i2c_gpio_init(&i2c_obj[i]);
101     }
102 }
103 
104 /**
105  * This function sets the sda pin.
106  *
107  * @param swm config class.
108  * @param The sda pin state.
109  */
swm_i2c_set_sda(void * data,rt_int32_t state)110 static void swm_i2c_set_sda(void *data, rt_int32_t state)
111 {
112     struct swm_soft_i2c_cfg *soft_i2c_cfg = (struct swm_soft_i2c_cfg *)data;
113     rt_pin_mode(soft_i2c_cfg->sda, PIN_MODE_OUTPUT_OD);
114     if (state)
115     {
116         rt_pin_write(soft_i2c_cfg->sda, PIN_HIGH);
117     }
118     else
119     {
120         rt_pin_write(soft_i2c_cfg->sda, PIN_LOW);
121     }
122 }
123 
124 /**
125  * This function sets the scl pin.
126  *
127  * @param swm config class.
128  * @param The scl pin state.
129  */
swm_i2c_set_scl(void * data,rt_int32_t state)130 static void swm_i2c_set_scl(void *data, rt_int32_t state)
131 {
132     struct swm_soft_i2c_cfg *soft_i2c_cfg = (struct swm_soft_i2c_cfg *)data;
133     rt_pin_mode(soft_i2c_cfg->scl, PIN_MODE_OUTPUT_OD);
134     if (state)
135     {
136         rt_pin_write(soft_i2c_cfg->scl, PIN_HIGH);
137     }
138     else
139     {
140         rt_pin_write(soft_i2c_cfg->scl, PIN_LOW);
141     }
142 }
143 
144 /**
145  * This function gets the sda pin state.
146  *
147  * @param The sda pin state.
148  */
swm_i2c_get_sda(void * data)149 static rt_int32_t swm_i2c_get_sda(void *data)
150 {
151     struct swm_soft_i2c_cfg *soft_i2c_cfg = (struct swm_soft_i2c_cfg *)data;
152     rt_pin_mode(soft_i2c_cfg->sda, PIN_MODE_INPUT_PULLUP);
153     return rt_pin_read(soft_i2c_cfg->sda);
154 }
155 
156 /**
157  * This function gets the scl pin state.
158  *
159  * @param The scl pin state.
160  */
swm_i2c_get_scl(void * data)161 static rt_int32_t swm_i2c_get_scl(void *data)
162 {
163     struct swm_soft_i2c_cfg *soft_i2c_cfg = (struct swm_soft_i2c_cfg *)data;
164     rt_pin_mode(soft_i2c_cfg->scl, PIN_MODE_INPUT_PULLUP);
165     return rt_pin_read(soft_i2c_cfg->scl);
166 }
167 
168 /**
169  * The time delay function.
170  *
171  * @param microseconds.
172  */
swm_i2c_udelay(rt_uint32_t us)173 static void swm_i2c_udelay(rt_uint32_t us)
174 {
175     rt_uint32_t ticks;
176     rt_uint32_t told, tnow, tcnt = 0;
177     rt_uint32_t reload = SysTick->LOAD;
178 
179     ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
180     told = SysTick->VAL;
181     while (1)
182     {
183         tnow = SysTick->VAL;
184         if (tnow != told)
185         {
186             if (tnow < told)
187             {
188                 tcnt += told - tnow;
189             }
190             else
191             {
192                 tcnt += reload - tnow + told;
193             }
194             told = tnow;
195             if (tcnt >= ticks)
196             {
197                 break;
198             }
199         }
200     }
201 }
202 
203 static const struct rt_i2c_bit_ops swm_i2c_bit_ops =
204 {
205         .data = RT_NULL,
206         .pin_init = swm_i2c_pin_init,
207         .set_sda = swm_i2c_set_sda,
208         .set_scl = swm_i2c_set_scl,
209         .get_sda = swm_i2c_get_sda,
210         .get_scl = swm_i2c_get_scl,
211         .udelay = swm_i2c_udelay,
212         .delay_us = 1,
213         .timeout = 100,
214         .i2c_pin_init_flag = RT_FALSE
215 };
216 
217 /* I2C initialization function */
swm_i2c_init(void)218 int swm_i2c_init(void)
219 {
220     rt_err_t result;
221 
222     for (rt_size_t i = 0; i < sizeof(i2c_obj) / sizeof(struct swm_soft_i2c_device); i++)
223     {
224         i2c_obj[i].ops = swm_i2c_bit_ops;
225         i2c_obj[i].ops.data = (void *)&swm_soft_i2c_cfg[i];
226         i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
227 
228         result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, swm_soft_i2c_cfg[i].name);
229         RT_ASSERT(result == RT_EOK);
230 
231         LOG_D("software simulation %s init done, pin scl: %d, pin sda %d",
232               swm_soft_i2c_cfg[i].name,
233               swm_soft_i2c_cfg[i].scl,
234               swm_soft_i2c_cfg[i].sda);
235     }
236 
237     return RT_EOK;
238 }
239 INIT_DEVICE_EXPORT(swm_i2c_init);
240 #endif /* BSP_USING_I2C */
241 #endif /* RT_USING_I2C */
242