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