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