1 /*
2  * Copyright (C) 2022-2024, Xiaohua Semiconductor Co., Ltd.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2022-04-28     CDT          first version
9  */
10 
11 /*******************************************************************************
12  * Include files
13  ******************************************************************************/
14 #include "drv_soft_i2c.h"
15 #include "board_config.h"
16 
17 #if defined(RT_USING_I2C)
18 
19 #if defined(BSP_USING_I2C1_SW) || defined(BSP_USING_I2C2_SW) || defined(BSP_USING_I2C3_SW) || \
20     defined(BSP_USING_I2C4_SW) || defined(BSP_USING_I2C5_SW) || defined(BSP_USING_I2C6_SW)
21 
22 /*******************************************************************************
23  * Local type definitions ('typedef')
24  ******************************************************************************/
25 
26 /*******************************************************************************
27  * Local pre-processor symbols/macros ('#define')
28  ******************************************************************************/
29 //#define DRV_DEBUG
30 #define LOG_TAG                         "drv.i2c"
31 #include <drv_log.h>
32 
33 /*******************************************************************************
34  * Global variable definitions (declared in header file with 'extern')
35  ******************************************************************************/
36 
37 /*******************************************************************************
38  * Local function prototypes ('static')
39  ******************************************************************************/
40 
41 /*******************************************************************************
42  * Local variable definitions ('static')
43  ******************************************************************************/
44 
45 static const struct hc32_soft_i2c_config soft_i2c_config[] =
46 {
47 #ifdef BSP_USING_I2C1_SW
48     I2C1_BUS_CONFIG,
49 #endif
50 #ifdef BSP_USING_I2C2_SW
51     I2C2_BUS_CONFIG,
52 #endif
53 #ifdef BSP_USING_I2C3_SW
54     I2C3_BUS_CONFIG,
55 #endif
56 #ifdef BSP_USING_I2C4_SW
57     I2C4_BUS_CONFIG,
58 #endif
59 #ifdef BSP_USING_I2C5_SW
60     I2C5_BUS_CONFIG,
61 #endif
62 #ifdef BSP_USING_I2C6_SW
63     I2C6_BUS_CONFIG,
64 #endif
65 };
66 
67 static struct hc32_soft_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
68 
69 /*******************************************************************************
70  * Function implementation - global ('extern') and local ('static')
71  ******************************************************************************/
72 /**
73  * This function initializes the i2c pin.
74  *
75  * @param Hc32 i2c driver class.
76  */
hc32_i2c_gpio_init(struct hc32_soft_i2c * i2c)77 static void hc32_i2c_gpio_init(struct hc32_soft_i2c *i2c)
78 {
79     struct hc32_soft_i2c_config *cfg = (struct hc32_soft_i2c_config *)i2c->ops.data;
80 
81     rt_pin_mode(cfg->scl_pin,   PIN_MODE_OUTPUT_OD);
82     rt_pin_mode(cfg->sda_pin,   PIN_MODE_OUTPUT_OD);
83     rt_pin_write(cfg->scl_pin,  PIN_HIGH);
84     rt_pin_write(cfg->sda_pin,  PIN_HIGH);
85 }
86 
hc32_i2c_pin_init(void)87 static void hc32_i2c_pin_init(void)
88 {
89     rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct hc32_soft_i2c);
90 
91     for (rt_size_t i = 0; i < obj_num; i++)
92     {
93         hc32_i2c_gpio_init(&i2c_obj[i]);
94     }
95 }
96 
97 /**
98  * This function sets the sda pin.
99  *
100  * @param Hc32 config class.
101  * @param The sda pin state.
102  */
hc32_set_sda(void * data,rt_int32_t state)103 static void hc32_set_sda(void *data, rt_int32_t state)
104 {
105     struct hc32_soft_i2c_config *cfg = (struct hc32_soft_i2c_config *)data;
106 
107     if (state)
108     {
109         rt_pin_write(cfg->sda_pin, PIN_HIGH);
110     }
111     else
112     {
113         rt_pin_write(cfg->sda_pin, PIN_LOW);
114     }
115 }
116 
117 /**
118  * This function sets the scl pin.
119  *
120  * @param Hc32 config class.
121  * @param The scl pin state.
122  */
hc32_set_scl(void * data,rt_int32_t state)123 static void hc32_set_scl(void *data, rt_int32_t state)
124 {
125     struct hc32_soft_i2c_config *cfg = (struct hc32_soft_i2c_config *)data;
126 
127     if (state)
128     {
129         rt_pin_write(cfg->scl_pin, PIN_HIGH);
130     }
131     else
132     {
133         rt_pin_write(cfg->scl_pin, PIN_LOW);
134     }
135 }
136 
137 /**
138  * This function gets the sda pin state.
139  *
140  * @param The sda pin state.
141  */
hc32_get_sda(void * data)142 static rt_int32_t hc32_get_sda(void *data)
143 {
144     struct hc32_soft_i2c_config *cfg = (struct hc32_soft_i2c_config *)data;
145     return rt_pin_read(cfg->sda_pin);
146 }
147 
148 /**
149  * This function gets the scl pin state.
150  *
151  * @param The scl pin state.
152  */
hc32_get_scl(void * data)153 static rt_int32_t hc32_get_scl(void *data)
154 {
155     struct hc32_soft_i2c_config *cfg = (struct hc32_soft_i2c_config *)data;
156     return rt_pin_read(cfg->scl_pin);
157 }
158 
159 /**
160  * The time delay function.
161  *
162  * @param microseconds.
163  */
hc32_udelay(rt_uint32_t us)164 static void hc32_udelay(rt_uint32_t us)
165 {
166     rt_uint32_t ticks;
167     rt_uint32_t told, tnow, tcnt = 0;
168     rt_uint32_t reload = SysTick->LOAD;
169 
170     ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
171     told = SysTick->VAL;
172     while (1)
173     {
174         tnow = SysTick->VAL;
175         if (tnow != told)
176         {
177             if (tnow < told)
178             {
179                 tcnt += told - tnow;
180             }
181             else
182             {
183                 tcnt += reload - tnow + told;
184             }
185             told = tnow;
186             if (tcnt >= ticks)
187             {
188                 break;
189             }
190         }
191     }
192 }
193 
194 static const struct rt_i2c_bit_ops hc32_bit_ops_default =
195 {
196     .data     = RT_NULL,
197     .pin_init = hc32_i2c_pin_init,
198     .set_sda  = hc32_set_sda,
199     .set_scl  = hc32_set_scl,
200     .get_sda  = hc32_get_sda,
201     .get_scl  = hc32_get_scl,
202     .udelay   = hc32_udelay,
203     .delay_us = 1,
204     .timeout  = 100,
205     .i2c_pin_init_flag = RT_FALSE
206 };
207 
208 /**
209  * if i2c is locked, this function will unlock it
210  *
211  * @param hc32 config class
212  *
213  * @return RT_EOK indicates successful unlock.
214  */
hc32_i2c_bus_unlock(const struct hc32_soft_i2c_config * cfg)215 static rt_err_t hc32_i2c_bus_unlock(const struct hc32_soft_i2c_config *cfg)
216 {
217     rt_uint32_t i = 0;
218 
219     if (PIN_LOW == rt_pin_read(cfg->sda_pin))
220     {
221         while (i++ < 9)
222         {
223             rt_pin_write(cfg->scl_pin, PIN_HIGH);
224             hc32_udelay(100);
225             rt_pin_write(cfg->scl_pin, PIN_LOW);
226             hc32_udelay(100);
227         }
228     }
229     if (PIN_LOW == rt_pin_read(cfg->sda_pin))
230     {
231         return -RT_ERROR;
232     }
233 
234     return RT_EOK;
235 }
236 
237 /* I2C initialization function */
hc32_soft_i2c_init(void)238 int hc32_soft_i2c_init(void)
239 {
240     rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct hc32_soft_i2c);
241     rt_err_t result;
242 
243     for (rt_size_t i = 0; i < obj_num; i++)
244     {
245         i2c_obj[i].ops          = hc32_bit_ops_default;
246         i2c_obj[i].ops.data     = (void *)&soft_i2c_config[i];
247         i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
248 
249         result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, soft_i2c_config[i].bus_name);
250         RT_ASSERT(result == RT_EOK);
251         hc32_i2c_bus_unlock(&soft_i2c_config[i]);
252     }
253 
254     return RT_EOK;
255 }
256 INIT_BOARD_EXPORT(hc32_soft_i2c_init);
257 
258 #endif
259 
260 #endif /* RT_USING_I2C */
261 
262 /*******************************************************************************
263  * EOF (not truncated)
264  ******************************************************************************/
265