1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2019-03-22     balanceTWK   first version
9  */
10 
11 #include <board.h>
12 #include "drv_soft_i2c.h"
13 
14 #include "wm_regs.h"
15 #include "wm_gpio.h"
16 #include "pin_map.h"
17 
18 #define DBG_SECTION_NAME     "soft_i2c"
19 #define DBG_COLOR
20 #define DBG_LEVEL           DBG_LOG
21 #include <rtdbg.h>
22 
23 #ifdef BSP_USING_SOFT_I2C
24 
25 #if !defined(BSP_USING_SOFT_I2C1) && !defined(BSP_USING_SOFT_I2C2) && !defined(BSP_USING_SOFT_I2C3)
26 #error "Please define at least one BSP_USING_SOFT_I2Cx"
27 #endif
28 
29 static const struct w60x_soft_i2c_config soft_i2c_config[] =
30 {
31 #ifdef BSP_USING_SOFT_I2C1
32     I2C1_BUS_CONFIG,
33 #endif
34 #ifdef BSP_USING_SOFT_I2C2
35     I2C2_BUS_CONFIG,
36 #endif
37 #ifdef BSP_USING_SOFT_I2C3
38     I2C3_BUS_CONFIG,
39 #endif
40 };
41 
42 static struct w60x_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
43 
44 /**
45  * This function initializes the i2c pin.
46  *
47  * @param w60x i2c dirver class.
48  */
w60x_i2c_gpio_init(struct w60x_i2c * i2c)49 static void w60x_i2c_gpio_init(struct w60x_i2c *i2c)
50 {
51     struct w60x_soft_i2c_config* cfg = (struct w60x_soft_i2c_config*)i2c->ops.data;
52     rt_int16_t scl,sda;
53 
54     scl = wm_get_pin(cfg->scl);
55     sda = wm_get_pin(cfg->sda);
56 
57     tls_gpio_cfg((enum tls_io_name)scl, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
58     tls_gpio_cfg((enum tls_io_name)sda, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
59 
60     tls_gpio_write((enum tls_io_name)scl, 1);
61     tls_gpio_write((enum tls_io_name)sda, 1);
62 }
63 
w60x_i2c_pin_init(void)64 static void w60x_i2c_pin_init(void)
65 {
66     rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct w60x_i2c);
67 
68     for(rt_size_t i = 0; i < obj_num; i++)
69     {
70         w60x_i2c_gpio_init(&i2c_obj[i]);
71     }
72 }
73 
74 /**
75  * This function sets the sda pin.
76  *
77  * @param w60x config class.
78  * @param The sda pin state.
79  */
w60x_set_sda(void * data,rt_int32_t state)80 static void w60x_set_sda(void *data, rt_int32_t state)
81 {
82     struct w60x_soft_i2c_config* cfg = (struct w60x_soft_i2c_config*)data;
83     rt_int16_t sda;
84 
85     sda = wm_get_pin(cfg->sda);
86 
87     if (state)
88     {
89         tls_gpio_cfg((enum tls_io_name)sda, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_PULLHIGH);
90     }
91     else
92     {
93         tls_gpio_cfg((enum tls_io_name)sda, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_FLOATING);
94         tls_gpio_write((enum tls_io_name)sda, 0);
95     }
96 }
97 
98 /**
99  * This function sets the scl pin.
100  *
101  * @param w60x config class.
102  * @param The scl pin state.
103  */
w60x_set_scl(void * data,rt_int32_t state)104 static void w60x_set_scl(void *data, rt_int32_t state)
105 {
106     struct w60x_soft_i2c_config* cfg = (struct w60x_soft_i2c_config*)data;
107     rt_int16_t scl;
108 
109     scl = wm_get_pin(cfg->scl);
110 
111     if (state)
112     {
113         tls_gpio_cfg((enum tls_io_name)scl, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_PULLHIGH);
114     }
115     else
116     {
117         tls_gpio_cfg((enum tls_io_name)scl, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_FLOATING);
118         tls_gpio_write((enum tls_io_name)scl, 0);
119     }
120 }
121 
122 /**
123  * This function gets the sda pin state.
124  *
125  * @param The sda pin state.
126  */
w60x_get_sda(void * data)127 static rt_int32_t w60x_get_sda(void *data)
128 {
129     struct w60x_soft_i2c_config* cfg = (struct w60x_soft_i2c_config*)data;
130     rt_int16_t sda;
131 
132     sda = wm_get_pin(cfg->sda);
133 
134     return tls_gpio_read((enum tls_io_name)sda);
135 }
136 
137 /**
138  * This function gets the scl pin state.
139  *
140  * @param The scl pin state.
141  */
w60x_get_scl(void * data)142 static rt_int32_t w60x_get_scl(void *data)
143 {
144     struct w60x_soft_i2c_config* cfg = (struct w60x_soft_i2c_config*)data;
145     rt_int16_t scl;
146 
147     scl = wm_get_pin(cfg->scl);
148 
149     return tls_gpio_read((enum tls_io_name)scl);
150 }
151 
152 
153 static const struct rt_i2c_bit_ops w60x_bit_ops_default =
154 {
155     .data     = RT_NULL,
156     .pin_init = w60x_i2c_pin_init,
157     .set_sda  = w60x_set_sda,
158     .set_scl  = w60x_set_scl,
159     .get_sda  = w60x_get_sda,
160     .get_scl  = w60x_get_scl,
161     .udelay   = rt_hw_us_delay,
162     .delay_us = 1,
163     .timeout  = 100,
164     .i2c_pin_init_flag = RT_FALSE
165 };
166 
167 /**
168  * if i2c is locked, this function will unlock it
169  *
170  * @param w60x config class
171  *
172  * @return RT_EOK indicates successful unlock.
173  */
w60x_i2c_bus_unlock(const struct w60x_soft_i2c_config * cfg)174 static rt_err_t w60x_i2c_bus_unlock(const struct w60x_soft_i2c_config *cfg)
175 {
176     rt_int32_t i = 0;
177 
178     if (PIN_LOW == rt_pin_read(cfg->sda))
179     {
180         while (i++ < 9)
181         {
182             rt_pin_write(cfg->scl, PIN_HIGH);
183             rt_hw_us_delay(100);
184             rt_pin_write(cfg->scl, PIN_LOW);
185             rt_hw_us_delay(100);
186         }
187     }
188     if (PIN_LOW == rt_pin_read(cfg->sda))
189     {
190         return -RT_ERROR;
191     }
192 
193     return RT_EOK;
194 }
195 
196 /* I2C initialization function */
rt_soft_i2c_init(void)197 int rt_soft_i2c_init(void)
198 {
199     rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct w60x_i2c);
200     rt_err_t result;
201 
202     for (rt_size_t i = 0; i < obj_num; i++)
203     {
204         i2c_obj[i].ops = w60x_bit_ops_default;
205         i2c_obj[i].ops.data = (void*)&soft_i2c_config[i];
206         i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
207 
208         result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, soft_i2c_config[i].bus_name);
209         RT_ASSERT(result == RT_EOK);
210         w60x_i2c_bus_unlock(&soft_i2c_config[i]);
211 
212         LOG_D("software simulation %s init done, pin scl: %d, pin sda %d",
213         soft_i2c_config[i].bus_name,
214         soft_i2c_config[i].scl,
215         soft_i2c_config[i].sda);
216     }
217 
218     return RT_EOK;
219 }
220 INIT_DEVICE_EXPORT(rt_soft_i2c_init);
221 
222 #endif /* BSP_USING_SOFT_I2C */
223