1 /*
2  * Copyright (c) 2006-2024, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2024-05-29     QT-one       first version
9  */
10 #include <rtdbg.h>
11 #include "drv_soft_i2c.h"
12 
13 #ifdef RT_USING_I2C
14 #if !defined(BSP_USING_I2C0_SW) && !defined(BSP_USING_I2C1_SW) && !defined(BSP_USING_I2C2_SW)
15     #error "Please define at least one BSP_USING_I2Cx_SW"
16     /* this driver can be disabled at menuconfig RT-Thread Components Device Drivers */
17 #endif
18 
19 /* ht32 software i2c config class */
20 struct ht32_soft_i2c_config
21 {
22     rt_uint8_t scl;
23     rt_uint8_t sda;
24     const char *bus_name;
25 };
26 /* ht32 software i2c dirver class */
27 struct ht32_soft_i2c
28 {
29     struct rt_i2c_bit_ops ops;
30     struct rt_i2c_bus_device i2c_bus;
31 };
32 
33 static rt_uint8_t scl_rw_flag = 0;
34 static rt_uint8_t sda_rw_flag = 0;
35 
36 static const struct ht32_soft_i2c_config soft_i2c_config[] =
37 {
38 #ifdef BSP_USING_I2C0_SW
39     {
40         .scl        = BSP_I2C0_SLC_PIN,
41         .sda        = BSP_I2C0_SDA_PIN,
42         .bus_name   = BSP_USING_I2C0_SW_NAME,
43     },
44 #endif
45 #ifdef BSP_USING_I2C1_SW
46     {
47         .scl        = BSP_I2C1_SLC_PIN,
48         .sda        = BSP_I2C1_SDA_PIN,
49         .bus_name   = BSP_USING_I2C1_SW_NAME,
50     },
51 #endif
52 #ifdef BSP_USING_I2C2_SW
53     {
54         .scl        = BSP_I2C2_SLC_PIN,
55         .sda        = BSP_I2C2_SDA_PIN,
56         .bus_name   = BSP_USING_I2C2_SW_NAME,
57     },
58 #endif
59 };
60 
61 static struct ht32_soft_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
62 
63 /* this function initializes the software i2c pin */
ht32_soft_i2c_gpio_init(struct ht32_soft_i2c * i2c)64 static void ht32_soft_i2c_gpio_init(struct ht32_soft_i2c *i2c)
65 {
66     struct ht32_soft_i2c_config* cfg = (struct ht32_soft_i2c_config*)i2c->ops.data;
67 
68     rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD);
69     rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
70 
71     rt_pin_write(cfg->scl, PIN_HIGH);
72     rt_pin_write(cfg->sda, PIN_HIGH);
73 }
74 /* this function sets the sda pin */
ht32_set_sda(void * data,rt_int32_t state)75 void ht32_set_sda(void *data, rt_int32_t state)
76 {
77     struct ht32_soft_i2c_config* cfg = (struct ht32_soft_i2c_config*)data;
78     if(sda_rw_flag != 0)
79     {
80         sda_rw_flag = 0;
81         rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
82     }
83     if (state)
84     {
85         rt_pin_write(cfg->sda, PIN_HIGH);
86     }
87     else
88     {
89         rt_pin_write(cfg->sda, PIN_LOW);
90     }
91 }
92 /* this function sets the scl pin */
ht32_set_scl(void * data,rt_int32_t state)93 void ht32_set_scl(void *data, rt_int32_t state)
94 {
95     struct ht32_soft_i2c_config* cfg = (struct ht32_soft_i2c_config*)data;
96     if(scl_rw_flag != 0)
97     {
98         scl_rw_flag = 0;
99         rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD);
100     }
101     if (state)
102     {
103         rt_pin_write(cfg->scl, PIN_HIGH);
104     }
105     else
106     {
107         rt_pin_write(cfg->scl, PIN_LOW);
108     }
109 }
110 /* this function gets the sda pin state */
ht32_get_sda(void * data)111 rt_int32_t ht32_get_sda(void *data)
112 {
113     struct ht32_soft_i2c_config* cfg = (struct ht32_soft_i2c_config*)data;
114 
115     if(sda_rw_flag == 0)
116     {
117         sda_rw_flag = 1;
118         rt_pin_mode(cfg->sda, PIN_MODE_INPUT);
119     }
120     return rt_pin_read(cfg->sda);
121 }
122 /* this function gets the scl pin state */
ht32_get_scl(void * data)123 rt_int32_t ht32_get_scl(void *data)
124 {
125     struct ht32_soft_i2c_config* cfg = (struct ht32_soft_i2c_config*)data;
126     if(scl_rw_flag == 0)
127     {
128         scl_rw_flag = 1;
129         rt_pin_mode(cfg->scl, PIN_MODE_INPUT);
130     }
131     return rt_pin_read(cfg->scl);
132 }
133 
ht32_udelay(rt_uint32_t us)134 void ht32_udelay(rt_uint32_t us)
135 {
136     rt_uint32_t ticks;
137     rt_uint32_t told, tnow, tcnt = 0;
138     rt_uint32_t reload = SysTick->LOAD;
139 
140     ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
141     told = SysTick->VAL;
142     while (1)
143     {
144         tnow = SysTick->VAL;
145         if (tnow != told)
146         {
147             if (tnow < told)
148             {
149                 tcnt += told - tnow;
150             }
151             else
152             {
153                 tcnt += reload - tnow + told;
154             }
155             told = tnow;
156             if (tcnt >= ticks)
157             {
158                 break;
159             }
160         }
161     }
162 }
163 
164 static const struct rt_i2c_bit_ops ht32_bit_ops_default =
165 {
166     .data     = RT_NULL,
167     .set_sda  = ht32_set_sda,
168     .set_scl  = ht32_set_scl,
169     .get_sda  = ht32_get_sda,
170     .get_scl  = ht32_get_scl,
171     .udelay   = ht32_udelay,
172     .delay_us = 1,
173     .timeout  = 100
174 };
175 
176 /* if i2c is locked, this function will unlock it */
ht32_soft_i2c_bus_unlock(const struct ht32_soft_i2c_config * cfg)177 static rt_err_t ht32_soft_i2c_bus_unlock(const struct ht32_soft_i2c_config *cfg)
178 {
179     rt_int32_t i = 0;
180     rt_pin_mode(cfg->sda, PIN_MODE_INPUT_PULLUP);
181     if (PIN_LOW == rt_pin_read(cfg->sda))
182     {
183         while (i++ < 9)
184         {
185             rt_pin_write(cfg->scl, PIN_HIGH);
186             ht32_udelay(100);
187             rt_pin_write(cfg->scl, PIN_LOW);
188             ht32_udelay(100);
189         }
190     }
191     if (PIN_LOW == rt_pin_read(cfg->sda))
192     {
193         return -RT_ERROR;
194     }
195     rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
196     return RT_EOK;
197 }
198 
199 /* i2c initialization function */
rt_sw_i2c_init(void)200 int rt_sw_i2c_init(void)
201 {
202     rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct ht32_soft_i2c);
203     rt_err_t result;
204 
205     for (int i = 0; i < obj_num; i++)
206     {
207         i2c_obj[i].ops = ht32_bit_ops_default;
208         i2c_obj[i].ops.data = (void*)&soft_i2c_config[i];
209         i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
210         ht32_soft_i2c_gpio_init(&i2c_obj[i]);
211 
212         result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, soft_i2c_config[i].bus_name);
213 
214         RT_ASSERT(result == RT_EOK);
215         ht32_soft_i2c_bus_unlock(&soft_i2c_config[i]);
216 
217         LOG_D("software simulation %s init done, pin scl: %d, pin sda %d",
218         soft_i2c_config[i].bus_name,
219         soft_i2c_config[i].scl,
220         soft_i2c_config[i].sda);
221     }
222     return result;
223 }
224 
225 INIT_BOARD_EXPORT(rt_sw_i2c_init);
226 
227 
228 #endif /* RT_USING_I2C */
229