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