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  * 2021-12-20     BruceOu           the first version
9  */
10 #include "drv_soft_i2c.h"
11 
12 #ifdef RT_USING_I2C
13 
14 #define LOG_TAG              "drv.i2c"
15 #include <rtdbg.h>
16 
17 #if !defined(BSP_USING_I2C0) && !defined(BSP_USING_I2C1) && !defined(BSP_USING_I2C2) && !defined(BSP_USING_I2C3)
18 #error "Please define at least one BSP_USING_I2Cx"
19 /* this driver can be disabled at menuconfig → RT-Thread Components → Device Drivers */
20 #endif
21 
22 static const struct gd32_soft_i2c_config soft_i2c_config[] =
23 {
24 #ifdef BSP_USING_I2C0
25     I2C0_BUS_CONFIG,
26 #endif
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 };
37 
38 static struct gd32_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
39 
40 /**
41   * @brief  This function initializes the i2c pin.
42   * @param  i2c
43   * @retval None
44   */
gd32_i2c_gpio_init(struct gd32_i2c * i2c)45 static void gd32_i2c_gpio_init(struct gd32_i2c *i2c)
46 {
47     struct gd32_soft_i2c_config* cfg = (struct gd32_soft_i2c_config*)i2c->ops.data;
48 
49     rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD);
50     rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
51 
52     rt_pin_write(cfg->scl, PIN_HIGH);
53     rt_pin_write(cfg->sda, PIN_HIGH);
54 }
55 
gd32_i2c_pin_init(void)56 static void gd32_i2c_pin_init(void)
57 {
58     rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct gd32_i2c);
59 
60     for(rt_size_t i = 0; i < obj_num; i++)
61     {
62         gd32_i2c_gpio_init(&i2c_obj[i]);
63     }
64 }
65 
66 /**
67   * @brief  This function sets the sda pin.
68   * @param  data, state
69   * @retval None
70   */
gd32_set_sda(void * data,rt_int32_t state)71 static void gd32_set_sda(void *data, rt_int32_t state)
72 {
73     struct gd32_soft_i2c_config* cfg = (struct gd32_soft_i2c_config*)data;
74     if (state)
75     {
76         rt_pin_write(cfg->sda, PIN_HIGH);
77     }
78     else
79     {
80         rt_pin_write(cfg->sda, PIN_LOW);
81     }
82 }
83 
84 /**
85   * @brief  This function sets the scl pin.
86   * @param  data, state
87   * @retval None
88   */
gd32_set_scl(void * data,rt_int32_t state)89 static void gd32_set_scl(void *data, rt_int32_t state)
90 {
91     struct gd32_soft_i2c_config* cfg = (struct gd32_soft_i2c_config*)data;
92     if (state)
93     {
94         rt_pin_write(cfg->scl, PIN_HIGH);
95     }
96     else
97     {
98         rt_pin_write(cfg->scl, PIN_LOW);
99     }
100 }
101 
102 /**
103   * @brief  This function gets the sda pin state.
104   * @param  data
105   * @retval None
106   */
gd32_get_sda(void * data)107 static rt_int32_t gd32_get_sda(void *data)
108 {
109     struct gd32_soft_i2c_config* cfg = (struct gd32_soft_i2c_config*)data;
110     return rt_pin_read(cfg->sda);
111 }
112 
113 
114 /**
115   * @brief  This function gets the scl pin state.
116   * @param  data
117   * @retval None
118   */
gd32_get_scl(void * data)119 static rt_int32_t gd32_get_scl(void *data)
120 {
121     struct gd32_soft_i2c_config* cfg = (struct gd32_soft_i2c_config*)data;
122     return rt_pin_read(cfg->scl);
123 }
124 
125 /**
126   * @brief  The time delay function.
127   * @param  us
128   * @retval None
129   */
gd32_udelay(rt_uint32_t us)130 static void gd32_udelay(rt_uint32_t us)
131 {
132     int i = ( rcu_clock_freq_get(CK_SYS) / 4000000 * us);
133     while(i)
134     {
135         i--;
136     }
137 }
138 
139 static const struct rt_i2c_bit_ops gd32_bit_ops_default =
140 {
141     .data     = RT_NULL,
142     .pin_init = gd32_i2c_pin_init,
143     .set_sda  = gd32_set_sda,
144     .set_scl  = gd32_set_scl,
145     .get_sda  = gd32_get_sda,
146     .get_scl  = gd32_get_scl,
147     .udelay   = gd32_udelay,
148     .delay_us = 1,
149     .timeout  = 100,
150     .i2c_pin_init_flag = RT_FALSE
151 };
152 
153 /**
154   * @brief  if i2c is locked, this function will unlock it
155   * @param  cfg
156   * @retval RT_EOK indicates successful unlock.
157   */
gd32_i2c_bus_unlock(const struct gd32_soft_i2c_config * cfg)158 static rt_err_t gd32_i2c_bus_unlock(const struct gd32_soft_i2c_config *cfg)
159 {
160     rt_int32_t i = 0;
161 
162     if (PIN_LOW == rt_pin_read(cfg->sda))
163     {
164         while (i++ < 9)
165         {
166             rt_pin_write(cfg->scl, PIN_HIGH);
167             gd32_udelay(100);
168             rt_pin_write(cfg->scl, PIN_LOW);
169             gd32_udelay(100);
170         }
171     }
172     if (PIN_LOW == rt_pin_read(cfg->sda))
173     {
174         return -RT_ERROR;
175     }
176 
177     return RT_EOK;
178 }
179 
180 /**
181   * @brief  I2C initialization function
182   * @param  None
183   * @retval RT_EOK indicates successful initialization.
184   */
rt_hw_i2c_init(void)185 int rt_hw_i2c_init(void)
186 {
187     rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct gd32_i2c);
188     rt_err_t result;
189 
190     for (rt_size_t i = 0; i < obj_num; i++)
191     {
192         i2c_obj[i].ops = gd32_bit_ops_default;
193         i2c_obj[i].ops.data = (void*)&soft_i2c_config[i];
194         i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
195 
196         result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, soft_i2c_config[i].bus_name);
197 
198         RT_ASSERT(result == RT_EOK);
199 
200         gd32_i2c_bus_unlock(&soft_i2c_config[i]);
201 
202         LOG_D("software simulation %s init done, pin scl: %d, pin sda %d",
203         soft_i2c_config[i].bus_name,
204         soft_i2c_config[i].scl,
205         soft_i2c_config[i].sda);
206     }
207 
208     return RT_EOK;
209 }
210 INIT_BOARD_EXPORT(rt_hw_i2c_init);
211 
212 #endif /* RT_USING_I2C */
213