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