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 * 2023/06/01 chushicheng first version
9 */
10 #include "drv_soft_i2c.h"
11
12 #ifdef BSP_USING_SOFT_I2C
13 #define DBG_LEVEL DBG_LOG
14 #include <rtdbg.h>
15 #define LOG_TAG "DRV.I2C"
16
17 static const struct pico_soft_i2c_config soft_i2c_config[] =
18 {
19 #ifdef BSP_USING_SOFT_I2C1
20 I2C1_BUS_CONFIG,
21 #endif
22 };
23
24 static struct pico_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
25
26 /**
27 * This function initializes the i2c pin.
28 *
29 * @param pico i2c dirver class.
30 */
pico_i2c_gpio_init(struct pico_i2c * i2c)31 static void pico_i2c_gpio_init(struct pico_i2c *i2c)
32 {
33 struct pico_soft_i2c_config* cfg = (struct pico_soft_i2c_config*)i2c->ops.data;
34
35 rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD);
36 rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
37 rt_pin_write(cfg->scl, PIN_HIGH);
38 rt_pin_write(cfg->sda, PIN_HIGH);
39 }
40
pico_i2c_pin_init(void)41 static void pico_i2c_pin_init(void)
42 {
43 rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct pico_i2c);
44
45 for(rt_size_t i = 0; i < obj_num; i++)
46 {
47 pico_i2c_gpio_init(&i2c_obj[i]);
48 }
49 }
50
51 /**
52 * This function sets the sda pin.
53 *
54 * @param pico config class.
55 * @param The sda pin state.
56 */
pico_set_sda(void * data,rt_int32_t state)57 static void pico_set_sda(void *data, rt_int32_t state)
58 {
59 struct pico_soft_i2c_config* cfg = (struct pico_soft_i2c_config*)data;
60 if (state)
61 {
62 rt_pin_write(cfg->sda, PIN_HIGH);
63 }
64 else
65 {
66 rt_pin_write(cfg->sda, PIN_LOW);
67 }
68 }
69
70 /**
71 * This function sets the scl pin.
72 *
73 * @param pico config class.
74 * @param The scl pin state.
75 */
pico_set_scl(void * data,rt_int32_t state)76 static void pico_set_scl(void *data, rt_int32_t state)
77 {
78 struct pico_soft_i2c_config* cfg = (struct pico_soft_i2c_config*)data;
79 if (state)
80 {
81 rt_pin_write(cfg->scl, PIN_HIGH);
82 }
83 else
84 {
85 rt_pin_write(cfg->scl, PIN_LOW);
86 }
87 }
88
89 /**
90 * This function gets the sda pin state.
91 *
92 * @param The sda pin state.
93 */
pico_get_sda(void * data)94 static rt_int32_t pico_get_sda(void *data)
95 {
96 struct pico_soft_i2c_config* cfg = (struct pico_soft_i2c_config*)data;
97 return rt_pin_read(cfg->sda);
98 }
99
100 /**
101 * This function gets the scl pin state.
102 *
103 * @param The scl pin state.
104 */
pico_get_scl(void * data)105 static rt_int32_t pico_get_scl(void *data)
106 {
107 struct pico_soft_i2c_config* cfg = (struct pico_soft_i2c_config*)data;
108 return rt_pin_read(cfg->scl);
109 }
110
111 /**
112 * The time delay function.
113 *
114 * @param microseconds.
115 */
pico_udelay(rt_uint32_t us)116 static void pico_udelay(rt_uint32_t us)
117 {
118 busy_wait_us_32(us);
119 }
120
121 static const struct rt_i2c_bit_ops pico_bit_ops_default =
122 {
123 .data = RT_NULL,
124 .pin_init = pico_i2c_pin_init,
125 .set_sda = pico_set_sda,
126 .set_scl = pico_set_scl,
127 .get_sda = pico_get_sda,
128 .get_scl = pico_get_scl,
129 .udelay = pico_udelay,
130 .delay_us = 1,
131 .timeout = 100,
132 .i2c_pin_init_flag = RT_FALSE
133 };
134
135 /**
136 * if i2c is locked, this function will unlock it
137 *
138 * @param pico config class
139 *
140 * @return RT_EOK indicates successful unlock.
141 */
pico_i2c_bus_unlock(const struct pico_soft_i2c_config * cfg)142 static rt_err_t pico_i2c_bus_unlock(const struct pico_soft_i2c_config *cfg)
143 {
144 rt_int32_t i = 0;
145
146 if (PIN_LOW == rt_pin_read(cfg->sda))
147 {
148 while (i++ < 9)
149 {
150 rt_pin_write(cfg->scl, PIN_HIGH);
151 pico_udelay(100);
152 rt_pin_write(cfg->scl, PIN_LOW);
153 pico_udelay(100);
154 }
155 }
156 if (PIN_LOW == rt_pin_read(cfg->sda))
157 {
158 return -RT_ERROR;
159 }
160
161 return RT_EOK;
162 }
163
164 /* I2C initialization function */
rt_soft_i2c_init(void)165 int rt_soft_i2c_init(void)
166 {
167 rt_err_t result;
168
169 for (rt_size_t i = 0; i < sizeof(i2c_obj) / sizeof(struct pico_i2c); i++)
170 {
171 i2c_obj[i].ops = pico_bit_ops_default;
172 i2c_obj[i].ops.data = (void*)&soft_i2c_config[i];
173 i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
174
175 result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, soft_i2c_config[i].bus_name);
176 RT_ASSERT(result == RT_EOK);
177 pico_i2c_bus_unlock(&soft_i2c_config[i]);
178
179 LOG_D("software simulation %s init done, pin scl: %d, pin sda %d",
180 soft_i2c_config[i].bus_name,
181 soft_i2c_config[i].scl,
182 soft_i2c_config[i].sda);
183 }
184
185 return RT_EOK;
186 }
187 INIT_DEVICE_EXPORT(rt_soft_i2c_init);
188
189 #endif /* BSP_USING_SOFT_I2C */
190