1 /*
2 * Copyright (C) 2020-2021 Alibaba Group Holding Limited
3 */
4
5 #include <string.h>
6 #include <aos/i2c_core.h>
7
8 #define XFER_TIMEOUT 1000
9
10 #define EVENT_XFER_COMPLETE ((uint32_t)1 << 0)
11 #define EVENT_XFER_ERROR ((uint32_t)1 << 1)
12
aos_i2c_get(aos_i2c_ref_t * ref,uint32_t id)13 aos_status_t aos_i2c_get(aos_i2c_ref_t *ref, uint32_t id)
14 {
15 return aos_dev_get(ref, AOS_DEV_TYPE_I2C, id);
16 }
17
aos_i2c_put(aos_i2c_ref_t * ref)18 void aos_i2c_put(aos_i2c_ref_t *ref)
19 {
20 aos_dev_put(ref);
21 }
22
transfer_sequence(aos_i2c_t * i2c,const aos_i2c_msg_t * msgs,size_t num_msgs)23 static aos_status_t transfer_sequence(aos_i2c_t *i2c, const aos_i2c_msg_t *msgs, size_t num_msgs)
24 {
25 const aos_i2c_msg_t *last_msg = NULL;
26 size_t last_pos = 0;
27
28 if (!(msgs[0].cfg & AOS_I2C_MCFG_RX))
29 memcpy(i2c->buf[0], msgs[0].buf, AOS_I2C_BUF_SIZE < msgs[0].count ? AOS_I2C_BUF_SIZE : msgs[0].count);
30
31 for (size_t i = 0, j = 0, pos = 0; i < num_msgs; j++) {
32 const aos_i2c_msg_t *msg = &msgs[i];
33 const aos_i2c_msg_t *next_msg;
34 bool msg_tail;
35 size_t next_pos;
36 uint32_t mask;
37 uint32_t val;
38 aos_status_t ret;
39
40 if (msg != last_msg) {
41 i2c->x.cfg = msg->cfg;
42 i2c->x.addr = msg->addr;
43 }
44
45 i2c->x.timeout = XFER_TIMEOUT;
46 i2c->x.len = (pos + AOS_I2C_BUF_SIZE < msg->count) ? AOS_I2C_BUF_SIZE : msg->count - pos;
47 i2c->x.pos[0] = 0;
48 i2c->x.pos[1] = 0;
49 msg_tail = (pos + i2c->x.len == msg->count);
50 i2c->x.flags = (j & 0x1) ? AOS_I2C_XF_BUF_IDX : 0;
51 i2c->x.flags |= (pos == 0) ? AOS_I2C_XF_MSG_HEAD : 0;
52 i2c->x.flags |= msg_tail ? AOS_I2C_XF_MSG_TAIL : 0;
53 i2c->x.flags |= (j == 0) ? AOS_I2C_XF_SEQ_HEAD : 0;
54 i2c->x.flags |= (msg_tail && i + 1 == num_msgs) ? AOS_I2C_XF_SEQ_TAIL : 0;
55
56 ret = i2c->ops->start_xfer(i2c);
57 if (ret)
58 return ret;
59
60 if (last_msg && (last_msg->cfg & AOS_I2C_MCFG_RX)) {
61 size_t last_len;
62
63 if (last_pos + AOS_I2C_BUF_SIZE < last_msg->count)
64 last_len = AOS_I2C_BUF_SIZE;
65 else
66 last_len = last_msg->count - last_pos;
67
68 memcpy(&((uint8_t *)last_msg->buf)[last_pos], i2c->buf[(j - 1) & 0x1], last_len);
69 }
70
71 if (msg_tail) {
72 next_msg = (i + 1 < num_msgs) ? &msgs[i + 1] : NULL;
73 next_pos = 0;
74 } else {
75 next_msg = msg;
76 next_pos = pos + i2c->x.len;
77 }
78
79 if (next_msg && !(next_msg->cfg & AOS_I2C_MCFG_RX)) {
80 size_t next_len;
81
82 if (next_pos + AOS_I2C_BUF_SIZE < next_msg->count)
83 next_len = AOS_I2C_BUF_SIZE;
84 else
85 next_len = next_msg->count - next_pos;
86
87 memcpy(i2c->buf[(j + 1) & 0x1], &((const uint8_t *)next_msg->buf)[next_pos], next_len);
88 }
89
90 mask = EVENT_XFER_COMPLETE | EVENT_XFER_ERROR;
91 if (aos_event_get(&i2c->event, mask, AOS_EVENT_OR, &val, i2c->x.timeout) || (val & EVENT_XFER_ERROR)) {
92 i2c->ops->abort_xfer(i2c);
93 aos_event_set(&i2c->event, 0, AOS_EVENT_AND);
94 return -EIO;
95 } else {
96 i2c->ops->finish_xfer(i2c);
97 aos_event_set(&i2c->event, 0, AOS_EVENT_AND);
98 }
99
100 last_msg = msg;
101 last_pos = pos;
102
103 if (msg_tail) {
104 pos = 0;
105 i++;
106 } else {
107 pos += i2c->x.len;
108 }
109 }
110
111 if (last_msg && (last_msg->cfg & AOS_I2C_MCFG_RX)) {
112 int index = (i2c->x.flags & AOS_I2C_XF_BUF_IDX) ? 1 : 0;
113 memcpy(&((uint8_t *)last_msg->buf)[last_pos], i2c->buf[index], i2c->x.len);
114 }
115
116 return 0;
117 }
118
aos_i2c_transfer(aos_i2c_ref_t * ref,const aos_i2c_msg_t * msgs,size_t num_msgs)119 aos_status_t aos_i2c_transfer(aos_i2c_ref_t *ref, const aos_i2c_msg_t *msgs, size_t num_msgs)
120 {
121 aos_i2c_t *i2c;
122 aos_status_t ret = 0;
123
124 if (!ref || !aos_dev_ref_is_valid(ref) || !msgs || num_msgs == 0)
125 return -EINVAL;
126
127 i2c = aos_container_of(ref->dev, aos_i2c_t, dev);
128
129 for (size_t i = 0; i < num_msgs; i++) {
130 const aos_i2c_msg_t *msg = &msgs[i];
131
132 if (msg->cfg & AOS_I2C_MCFG_ADDR_10) {
133 if (!(i2c->flags & AOS_I2C_F_ADDR_10))
134 return -EINVAL;
135
136 if (msg->addr & ~(uint16_t)0x3FF)
137 return -EINVAL;
138 } else {
139 if (msg->addr & ~(uint16_t)0x7F)
140 return -EINVAL;
141
142 if (msg->addr <= 0x07 || msg->addr >= 0x78)
143 return -EINVAL;
144 }
145
146 if (msg->count == 0 || !msg->buf)
147 return -EINVAL;
148 }
149
150 for (size_t i = 0, j = 0; i < num_msgs; i++) {
151 if (i + 1 < num_msgs &&
152 (msgs[i].cfg & AOS_I2C_MCFG_ADDR_10) == (msgs[i + 1].cfg & AOS_I2C_MCFG_ADDR_10) &&
153 msgs[i].addr == msgs[i + 1].addr)
154 continue;
155
156 aos_dev_lock(ref->dev);
157 ret = transfer_sequence(i2c, &msgs[j], i + 1 - j);
158 aos_dev_unlock(ref->dev);
159 if (ret)
160 break;
161
162 j = i + 1;
163 }
164
165 return ret;
166 }
167
dev_i2c_unregister(aos_dev_t * dev)168 static void dev_i2c_unregister(aos_dev_t *dev)
169 {
170 aos_i2c_t *i2c = aos_container_of(dev, aos_i2c_t, dev);
171
172 aos_event_free(&i2c->event);
173
174 if (i2c->ops->unregister)
175 i2c->ops->unregister(i2c);
176 }
177
dev_i2c_get(aos_dev_ref_t * ref)178 static aos_status_t dev_i2c_get(aos_dev_ref_t *ref)
179 {
180 aos_i2c_t *i2c = aos_container_of(ref->dev, aos_i2c_t, dev);
181 aos_status_t ret;
182
183 if (!aos_dev_ref_is_first(ref))
184 return 0;
185
186 ret = i2c->ops->startup(i2c);
187 if (ret)
188 return ret;
189
190 return 0;
191 }
192
dev_i2c_put(aos_dev_ref_t * ref)193 static void dev_i2c_put(aos_dev_ref_t *ref)
194 {
195 aos_i2c_t *i2c = aos_container_of(ref->dev, aos_i2c_t, dev);
196
197 if (!aos_dev_ref_is_last(ref))
198 return;
199
200 i2c->ops->shutdown(i2c);
201 }
202
203 static const aos_dev_ops_t dev_i2c_ops = {
204 .unregister = dev_i2c_unregister,
205 .get = dev_i2c_get,
206 .put = dev_i2c_put,
207 };
208
aos_i2c_register(aos_i2c_t * i2c)209 aos_status_t aos_i2c_register(aos_i2c_t *i2c)
210 {
211 aos_status_t ret;
212
213 if (!i2c)
214 return -EINVAL;
215
216 if (!i2c->ops || !i2c->ops->startup || !i2c->ops->shutdown ||
217 !i2c->ops->start_xfer || !i2c->ops->finish_xfer || !i2c->ops->abort_xfer)
218 return -EINVAL;
219
220 if (i2c->hz == 0)
221 return -EINVAL;
222
223 i2c->dev.type = AOS_DEV_TYPE_I2C;
224 i2c->dev.ops = &dev_i2c_ops;
225 #ifdef AOS_COMP_VFS
226 i2c->dev.vfs_helper.name[0] = '\0';
227 i2c->dev.vfs_helper.ops = NULL;
228 #endif
229 aos_spin_lock_init(&i2c->lock);
230
231 ret = aos_event_new(&i2c->event, 0);
232 if (ret)
233 return ret;
234
235 ret = aos_dev_register(&i2c->dev);
236 if (ret) {
237 aos_event_free(&i2c->event);
238 return ret;
239 }
240
241 return 0;
242 }
243
aos_i2c_unregister(uint32_t id)244 aos_status_t aos_i2c_unregister(uint32_t id)
245 {
246 return aos_dev_unregister(AOS_DEV_TYPE_I2C, id);
247 }
248
aos_i2c_hard_push(aos_i2c_t * i2c,void * tx_buf,size_t count)249 size_t aos_i2c_hard_push(aos_i2c_t *i2c, void *tx_buf, size_t count)
250 {
251 if (i2c->x.pos[0] + count > i2c->x.len)
252 count = i2c->x.len - i2c->x.pos[0];
253
254 if (!(i2c->x.cfg & AOS_I2C_MCFG_RX) && tx_buf) {
255 const uint8_t *buf = i2c->buf[(i2c->x.flags & AOS_I2C_XF_BUF_IDX) ? 1 : 0];
256
257 for (size_t i = 0; i < count; i++)
258 ((uint8_t *)tx_buf)[i] = buf[i2c->x.pos[0] + i];
259 }
260
261 i2c->x.pos[0] += count;
262
263 return count;
264 }
265
aos_i2c_hard_pull(aos_i2c_t * i2c,const void * rx_buf,size_t count)266 bool aos_i2c_hard_pull(aos_i2c_t *i2c, const void *rx_buf, size_t count)
267 {
268 if (i2c->x.pos[1] + count > i2c->x.pos[0])
269 count = i2c->x.pos[0] - i2c->x.pos[1];
270
271 if ((i2c->x.cfg & AOS_I2C_MCFG_RX) && rx_buf) {
272 uint8_t *buf = i2c->buf[(i2c->x.flags & AOS_I2C_XF_BUF_IDX) ? 1 : 0];
273
274 for (size_t i = 0; i < count; i++)
275 buf[i2c->x.pos[1] + i] = ((const uint8_t *)rx_buf)[i];
276 }
277
278 i2c->x.pos[1] += count;
279 if (i2c->x.pos[1] == i2c->x.len) {
280 aos_event_set(&i2c->event, EVENT_XFER_COMPLETE, AOS_EVENT_OR);
281 return true;
282 }
283
284 return false;
285 }
286
aos_i2c_hard_fail(aos_i2c_t * i2c)287 void aos_i2c_hard_fail(aos_i2c_t *i2c)
288 {
289 aos_event_set(&i2c->event, EVENT_XFER_ERROR, AOS_EVENT_OR);
290 }
291