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