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-12-07     wumingzi     first version
9  */
10 #include <rtthread.h>
11 #include <rtdevice.h>
12 #define LOG_TAG     "drv.i2c"
13 #ifdef RT_USING_I2C
14 #ifdef BSP_USING_SW_I2C
15 #include "rthw.h"
16 #include "rttypes.h"
17 #include <rtdbg.h>
18 #include "driver/gpio.h"
19 #include "drv_sw_i2c.h"
20 
21 #if defined(BSP_USING_SW_I2C0)
22 #define SW_I2C0_BUS_CONFIG                               \
23     {                                                    \
24         .scl = BSP_SW_I2C0_SCL_PIN,                      \
25         .sda = BSP_SW_I2C0_SDA_PIN,                      \
26         .bus_name = "i2c0",                              \
27     }
28 #endif
29 
30 static const struct esp32c3_soft_i2c_config soft_i2c_config[] =
31 {
32 #if defined(BSP_USING_SW_I2C0)
33     SW_I2C0_BUS_CONFIG,
34 #endif
35 };
36 
37 static struct esp32c3_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
38 
39 /**
40   * @brief  This function initializes the i2c pin.
41   * @param  i2c
42   * @retval None
43   */
esp32c3_i2c_gpio_init(struct esp32c3_i2c * i2c)44 static void esp32c3_i2c_gpio_init(struct esp32c3_i2c *i2c)
45 {
46     struct esp32c3_soft_i2c_config* cfg = (struct esp32c3_soft_i2c_config*)i2c->ops.data;
47     rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD);
48     rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
49 
50     gpio_set_pull_mode(cfg->sda, GPIO_FLOATING);
51     gpio_set_pull_mode(cfg->scl, GPIO_FLOATING);
52 
53     gpio_set_level(cfg->scl, PIN_HIGH);
54     gpio_set_level(cfg->sda, PIN_HIGH);
55 }
56 
57 /**
58   * @brief  This function sets the sda pin.
59   * @param  data, state
60   * @retval None
61   */
esp32c3_set_sda(void * data,rt_int32_t state)62 static void esp32c3_set_sda(void *data, rt_int32_t state)
63 {
64     struct esp32c3_soft_i2c_config* cfg = (struct esp32c3_soft_i2c_config*)data;
65     /*rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);*/
66     if (state)
67     {
68         gpio_set_level(cfg->sda, PIN_HIGH);
69     }
70     else
71     {
72         gpio_set_level(cfg->sda, PIN_LOW);
73     }
74 }
75 
76 /**
77   * @brief  This function sets the scl pin.
78   * @param  data, state
79   * @retval None
80   */
esp32c3_set_scl(void * data,rt_int32_t state)81 static void esp32c3_set_scl(void *data, rt_int32_t state)
82 {
83     struct esp32c3_soft_i2c_config* cfg = (struct esp32c3_soft_i2c_config*)data;
84     if (state)
85     {
86         gpio_set_level(cfg->scl, PIN_HIGH);
87     }
88     else
89     {
90         gpio_set_level(cfg->scl, PIN_LOW);
91     }
92 }
93 
94 /**
95   * @brief  This function gets the sda pin state.
96   * @param  data
97   * @retval None
98   */
esp32c3_get_sda(void * data)99 static rt_int32_t esp32c3_get_sda(void *data)
100 {
101     struct esp32c3_soft_i2c_config* cfg = (struct esp32c3_soft_i2c_config*)data;
102     return gpio_get_level(cfg->sda);
103 }
104 
105 /**
106   * @brief  This function gets the scl pin state.
107   * @param  data
108   * @retval None
109   */
esp32c3_get_scl(void * data)110 static rt_int32_t esp32c3_get_scl(void *data)
111 {
112     struct esp32c3_soft_i2c_config* cfg = (struct esp32c3_soft_i2c_config*)data;
113     return gpio_get_level(cfg->scl);
114 }
115 
116 /**
117   * @brief  The time delay function.
118   * @param  us
119   * @retval None
120   */
esp32c3_udelay(rt_uint32_t us)121 static void esp32c3_udelay(rt_uint32_t us)
122 {
123     rt_hw_us_delay(us);
124 }
125 
126 /*
127  * if i2c is locked, this function will unlock it
128  *
129  * @param esp32 config class
130  *
131  * @return RT_EOK indicates successful unlock.
132  */
133 /* */
esp32c3_i2c_bus_unlock(const struct esp32c3_soft_i2c_config * cfg)134 static rt_err_t esp32c3_i2c_bus_unlock(const struct esp32c3_soft_i2c_config *cfg)
135 {
136     rt_int32_t i = 0;
137 
138     if (PIN_LOW == rt_pin_read(cfg->sda))
139     {
140         /* 输出9个时钟 解锁IIC死锁  */
141         while (i++ < 9)
142         {
143             gpio_set_level(cfg->scl, PIN_HIGH);
144             esp32c3_udelay(100);
145             gpio_set_level(cfg->scl, PIN_LOW);
146             esp32c3_udelay(100);
147         }
148     }
149     if (PIN_LOW == gpio_get_level(cfg->sda))
150     {
151         return -RT_ERROR;
152     }
153     return RT_EOK;
154 }
155 
156 static const struct rt_i2c_bit_ops esp32c3_bit_ops_default =
157 {
158     .data     = RT_NULL,
159     .set_sda  = esp32c3_set_sda,
160     .set_scl  = esp32c3_set_scl,
161     .get_sda  = esp32c3_get_sda,
162     .get_scl  = esp32c3_get_scl,
163     .udelay   = esp32c3_udelay,
164     .delay_us = 1,
165     .timeout  = 100
166 };
167 
rt_sw_i2c_init(void)168 int rt_sw_i2c_init(void)
169 {
170     /* I2C设备数量 */
171     rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct esp32c3_i2c);
172     rt_err_t result;
173     /* 循环初始化 */
174     for (int i = 0; i < obj_num; i++)
175     {
176         /* 注册方法 */
177         i2c_obj[i].ops = esp32c3_bit_ops_default;
178         /* 设备硬件数据 */
179         i2c_obj[i].ops.data = (void*)&soft_i2c_config[i];
180         /* 保存设备方法 */
181         i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
182 
183         esp32c3_i2c_gpio_init(&i2c_obj[i]);
184         result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, soft_i2c_config[i].bus_name);
185         RT_ASSERT(result == RT_EOK);
186 
187         esp32c3_i2c_bus_unlock(&soft_i2c_config[i]);
188         LOG_D("software simulation %s init done, pin scl: %d, pin sda %d",
189                                             soft_i2c_config[i].bus_name,
190                                             soft_i2c_config[i].scl,
191                                             soft_i2c_config[i].sda);
192     }
193 
194     return RT_EOK;
195 }
196 INIT_APP_EXPORT(rt_sw_i2c_init);
197 
198 #endif /* BSP_USING_SW_I2C */
199 #endif /* RT_USING_I2C */