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/12/01     Raman Gopalan    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 avr32_soft_i2c_config soft_i2c_config[] =
18 {
19 #ifdef BSP_USING_SOFT_I2C1
20     I2C1_BUS_CONFIG,
21 #endif
22 };
23 
24 static struct avr32_i2c i2c_obj[sizeof(soft_i2c_config) / sizeof(soft_i2c_config[0])];
25 
26 /**
27  * This function initializes the I2C pin.
28  *
29  * @param AVR32 I2C driver class.
30  */
avr32_i2c_gpio_init(struct avr32_i2c * i2c)31 static void avr32_i2c_gpio_init(struct avr32_i2c *i2c)
32 {
33     struct avr32_soft_i2c_config* cfg = (struct avr32_soft_i2c_config*)i2c->ops.data;
34 
35     rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD);
36     gpio_set_gpio_open_drain_pin(cfg->scl);
37 
38     rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);
39     gpio_set_gpio_open_drain_pin(cfg->sda);
40 }
41 
avr32_i2c_pin_init(void)42 static void avr32_i2c_pin_init(void)
43 {
44     rt_size_t obj_num = sizeof(i2c_obj) / sizeof(struct avr32_i2c);
45 
46     for(rt_size_t i = 0; i < obj_num; i++)
47     {
48         avr32_i2c_gpio_init(&i2c_obj[i]);
49     }
50 }
51 
52 /**
53  * This function sets the SDA pin.
54  *
55  * @param AVR32 config class.
56  * @param The SDA pin state.
57  */
avr32_set_sda(void * data,rt_int32_t state)58 static void avr32_set_sda(void *data, rt_int32_t state)
59 {
60     struct avr32_soft_i2c_config* cfg = (struct avr32_soft_i2c_config*)data;
61     if (state)
62     {
63     gpio_set_gpio_open_drain_pin(cfg->sda);
64     }
65     else
66     {
67     gpio_clr_gpio_open_drain_pin(cfg->sda);
68     }
69 }
70 
71 /**
72  * This function sets the SCL pin.
73  *
74  * @param AVR32 config class.
75  * @param The SCL pin state.
76  */
avr32_set_scl(void * data,rt_int32_t state)77 static void avr32_set_scl(void *data, rt_int32_t state)
78 {
79     struct avr32_soft_i2c_config* cfg = (struct avr32_soft_i2c_config*)data;
80     if (state)
81     {
82     gpio_set_gpio_open_drain_pin(cfg->scl);
83     }
84     else
85     {
86     gpio_clr_gpio_open_drain_pin(cfg->scl);
87     }
88 }
89 
90 /**
91  * This function gets the SDA pin state.
92  *
93  * @param The SDA pin state.
94  */
avr32_get_sda(void * data)95 static rt_int32_t avr32_get_sda(void *data)
96 {
97     struct avr32_soft_i2c_config* cfg = (struct avr32_soft_i2c_config*)data;
98     return gpio_get_gpio_open_drain_pin_output_value(cfg->sda);
99 }
100 
101 /**
102  * This function gets the SCL pin state.
103  *
104  * @param The SCL pin state.
105  */
avr32_get_scl(void * data)106 static rt_int32_t avr32_get_scl(void *data)
107 {
108     struct avr32_soft_i2c_config* cfg = (struct avr32_soft_i2c_config*)data;
109     return gpio_get_gpio_open_drain_pin_output_value(cfg->scl);
110 }
111 
112 static const struct rt_i2c_bit_ops avr32_bit_ops_default =
113 {
114     .data     = RT_NULL,
115     .pin_init = avr32_i2c_pin_init,
116     .set_sda  = avr32_set_sda,
117     .set_scl  = avr32_set_scl,
118     .get_sda  = avr32_get_sda,
119     .get_scl  = avr32_get_scl,
120     .udelay   = rt_hw_us_delay,
121     .delay_us = 1,
122     .timeout  = 100,
123     .i2c_pin_init_flag = RT_FALSE
124 };
125 
126 /**
127  * If I2C is locked, this function will unlock it.
128  *
129  * @param AVR32 config class
130  *
131  * @return RT_EOK indicates successful unlock.
132  */
avr32_i2c_bus_unlock(const struct avr32_soft_i2c_config * cfg)133 static rt_err_t avr32_i2c_bus_unlock(const struct avr32_soft_i2c_config *cfg)
134 {
135     rt_int32_t i = 0;
136 
137     if (PIN_LOW == gpio_get_gpio_open_drain_pin_output_value(cfg->sda))
138     {
139         while (i++ < 9)
140         {
141         gpio_set_gpio_open_drain_pin(cfg->scl);
142         rt_hw_us_delay(100);
143         gpio_clr_gpio_open_drain_pin(cfg->scl);
144         rt_hw_us_delay(100);
145         }
146     }
147     if (PIN_LOW == gpio_get_gpio_open_drain_pin_output_value(cfg->sda))
148     {
149         return -RT_ERROR;
150     }
151 
152     return RT_EOK;
153 }
154 
155 /* I2C initialization function */
rt_sw_i2c_init(void)156 int rt_sw_i2c_init(void)
157 {
158     rt_err_t result;
159     rt_size_t i;
160 
161     for (i = 0; i < sizeof(i2c_obj) / sizeof(struct avr32_i2c); i++)
162     {
163         i2c_obj[i].ops = avr32_bit_ops_default;
164         i2c_obj[i].ops.data = (void*)&soft_i2c_config[i];
165         i2c_obj[i].i2c_bus.priv = &i2c_obj[i].ops;
166 
167         result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c_bus, soft_i2c_config[i].bus_name);
168         RT_ASSERT(result == RT_EOK);
169         avr32_i2c_bus_unlock(&soft_i2c_config[i]);
170 
171         LOG_D("Software simulation %s init done, pin SCL: %d, pin SDA %d",
172         soft_i2c_config[i].bus_name,
173         soft_i2c_config[i].scl,
174         soft_i2c_config[i].sda);
175     }
176 
177     return RT_EOK;
178 }
179 
180 #endif /* BSP_USING_SOFT_I2C */
181