1 /*
2 * Copyright (c) 2017 BayLibre, SAS
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
8 #include <zephyr/drivers/clock_control.h>
9 #include <zephyr/sys/util.h>
10 #include <zephyr/kernel.h>
11 #include <errno.h>
12 #include <zephyr/drivers/i2c.h>
13
14 #define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_DECLARE(main);
17
18 struct i2c_virtual_data {
19 sys_slist_t targets;
20 };
21
i2c_virtual_runtime_configure(const struct device * dev,uint32_t config)22 int i2c_virtual_runtime_configure(const struct device *dev, uint32_t config)
23 {
24 return 0;
25 }
26
find_address(struct i2c_virtual_data * data,uint16_t address,bool is_10bit)27 static struct i2c_target_config *find_address(struct i2c_virtual_data *data,
28 uint16_t address, bool is_10bit)
29 {
30 struct i2c_target_config *cfg = NULL;
31 sys_snode_t *node;
32 bool search_10bit;
33
34 SYS_SLIST_FOR_EACH_NODE(&data->targets, node) {
35 cfg = CONTAINER_OF(node, struct i2c_target_config, node);
36
37 search_10bit = (cfg->flags & I2C_TARGET_FLAGS_ADDR_10_BITS);
38
39 if (cfg->address == address && search_10bit == is_10bit) {
40 return cfg;
41 }
42 }
43
44 return NULL;
45 }
46
47 /* Attach I2C targets */
i2c_virtual_target_register(const struct device * dev,struct i2c_target_config * config)48 int i2c_virtual_target_register(const struct device *dev,
49 struct i2c_target_config *config)
50 {
51 struct i2c_virtual_data *data = dev->data;
52
53 if (!config) {
54 return -EINVAL;
55 }
56
57 /* Check the address is unique */
58 if (find_address(data, config->address,
59 (config->flags & I2C_TARGET_FLAGS_ADDR_10_BITS))) {
60 return -EINVAL;
61 }
62
63 sys_slist_append(&data->targets, &config->node);
64
65 return 0;
66 }
67
68
i2c_virtual_target_unregister(const struct device * dev,struct i2c_target_config * config)69 int i2c_virtual_target_unregister(const struct device *dev,
70 struct i2c_target_config *config)
71 {
72 struct i2c_virtual_data *data = dev->data;
73
74 if (!config) {
75 return -EINVAL;
76 }
77
78 if (!sys_slist_find_and_remove(&data->targets, &config->node)) {
79 return -EINVAL;
80 }
81
82 return 0;
83 }
84
i2c_virtual_msg_write(const struct device * dev,struct i2c_msg * msg,struct i2c_target_config * config,bool prev_write)85 static int i2c_virtual_msg_write(const struct device *dev,
86 struct i2c_msg *msg,
87 struct i2c_target_config *config,
88 bool prev_write)
89 {
90 unsigned int len = 0U;
91 uint8_t *buf = msg->buf;
92 int ret;
93
94 if (!prev_write) {
95 config->callbacks->write_requested(config);
96 }
97
98 len = msg->len;
99 while (len) {
100
101 ret = config->callbacks->write_received(config, *buf);
102 if (ret) {
103 goto error;
104 }
105 buf++;
106 len--;
107 }
108
109 if (!(msg->flags & I2C_MSG_RESTART) && msg->flags & I2C_MSG_STOP) {
110 config->callbacks->stop(config);
111 }
112
113 return 0;
114 error:
115 LOG_DBG("%s: NACK", __func__);
116
117 return -EIO;
118 }
119
i2c_virtual_msg_read(const struct device * dev,struct i2c_msg * msg,struct i2c_target_config * config)120 static int i2c_virtual_msg_read(const struct device *dev, struct i2c_msg *msg,
121 struct i2c_target_config *config)
122 {
123 unsigned int len = msg->len;
124 uint8_t *buf = msg->buf;
125
126 if (!msg->len) {
127 return 0;
128 }
129
130 config->callbacks->read_requested(config, buf);
131 buf++;
132 len--;
133
134 while (len) {
135 config->callbacks->read_processed(config, buf);
136 buf++;
137 len--;
138 }
139
140 if (!(msg->flags & I2C_MSG_RESTART) && msg->flags & I2C_MSG_STOP) {
141 config->callbacks->stop(config);
142 }
143
144 return 0;
145 }
146
147 #define OPERATION(msg) (((struct i2c_msg *) msg)->flags & I2C_MSG_RW_MASK)
148
i2c_virtual_transfer(const struct device * dev,struct i2c_msg * msg,uint8_t num_msgs,uint16_t target)149 static int i2c_virtual_transfer(const struct device *dev, struct i2c_msg *msg,
150 uint8_t num_msgs, uint16_t target)
151 {
152 struct i2c_virtual_data *data = dev->data;
153 struct i2c_msg *current, *next;
154 struct i2c_target_config *cfg;
155 bool is_write = false;
156 int ret = 0;
157
158 cfg = find_address(data, target, (msg->flags & I2C_TARGET_FLAGS_ADDR_10_BITS));
159 if (!cfg) {
160 return -EIO;
161 }
162
163 current = msg;
164 current->flags |= I2C_MSG_RESTART;
165 while (num_msgs > 0) {
166 if (num_msgs > 1) {
167 next = current + 1;
168
169 /*
170 * Stop or restart condition between messages
171 * of different directions is required
172 */
173 if (OPERATION(current) != OPERATION(next)) {
174 if (!(next->flags & I2C_MSG_RESTART)) {
175 ret = -EINVAL;
176 break;
177 }
178 }
179 }
180
181 /* Stop condition is required for the last message */
182 if ((num_msgs == 1U) && !(current->flags & I2C_MSG_STOP)) {
183 ret = -EINVAL;
184 break;
185 }
186
187 if ((current->flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
188 ret = i2c_virtual_msg_write(dev, current,
189 cfg, is_write);
190 is_write = true;
191 } else {
192 ret = i2c_virtual_msg_read(dev, current, cfg);
193 is_write = false;
194 }
195
196 if (ret < 0) {
197 break;
198 }
199
200 current++;
201 num_msgs--;
202 }
203
204 return ret;
205 }
206
207 static DEVICE_API(i2c, api_funcs) = {
208 .configure = i2c_virtual_runtime_configure,
209 .transfer = i2c_virtual_transfer,
210 .target_register = i2c_virtual_target_register,
211 .target_unregister = i2c_virtual_target_unregister,
212 };
213
i2c_virtual_init(const struct device * dev)214 static int i2c_virtual_init(const struct device *dev)
215 {
216 struct i2c_virtual_data *data = dev->data;
217
218 sys_slist_init(&data->targets);
219
220 return 0;
221 }
222
223 static struct i2c_virtual_data i2c_virtual_dev_data_0;
224
225 DEVICE_DEFINE(i2c_virtual_0, CONFIG_I2C_VIRTUAL_NAME, &i2c_virtual_init,
226 NULL, &i2c_virtual_dev_data_0, NULL,
227 POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
228 &api_funcs);
229