1 /*
2  * Copyright (c) 2022 OpenLuat & AirM2M
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy of
5  * this software and associated documentation files (the "Software"), to deal in
6  * the Software without restriction, including without limitation the rights to
7  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8  * the Software, and to permit persons to whom the Software is furnished to do so,
9  * subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20  */
21 
22 #include "user.h"
23 
24 #define IIC_DBG DBG
25 enum
26 {
27     I2C_STATE_FREE,
28     I2C_STATE_INIT_STOP,
29     I2C_STATE_ERROR_STOP,
30     I2C_STATE_WRITE_ADDRESS,
31     I2C_STATE_WRITE_REG,
32     I2C_STATE_WRITE_DATA,
33     I2C_STATE_WRITE_STOP,
34     I2C_STATE_READ_ADDRESS_WR,
35     I2C_STATE_READ_REG_WR,
36     I2C_STATE_READ_ADDRESS_RD,
37     I2C_STATE_READ_DATA_RD,
38     I2C_STATE_READ_STOP,
39 };
40 
41 typedef struct
42 {
43     const I2C_TypeDef *RegBase;
44     const int IrqLine;
45     Buffer_Struct DataBuf;
46     CBFuncEx_t Callback;
47     void *pParam;
48     HANDLE Sem;
49     I2C_CommonRegDataStruct *RegQueue;
50     uint32_t TotalQueueNum;
51     uint32_t CurQueuePos;
52     int32_t Result;
53     uint16_t TimeoutMs;
54     uint16_t ChipAddress;
55     uint8_t ChipAddressLen;
56     uint8_t RegAddress;
57     uint8_t State;
58     uint8_t IsBusy;
59     uint8_t IsBlockMode;
60 }I2C_CtrlStruct;
61 static I2C_CtrlStruct prvI2C = {
62         I2C0,
63         I2C0_IRQn,
64 };
65 
prvI2C_Done(int32_t Result)66 static void prvI2C_Done(int32_t Result)
67 {
68     prvI2C.State = I2C_STATE_FREE;
69     prvI2C.Result = Result;
70     prvI2C.IsBusy = 0;
71 #ifdef __BUILD_OS__
72     if (prvI2C.IsBlockMode) OS_MutexRelease(prvI2C.Sem);
73 #endif
74     prvI2C.Callback(I2C_ID0, prvI2C.pParam);
75 }
76 
prvI2C_DummyCB(void * pData,void * pParam)77 static int32_t prvI2C_DummyCB(void *pData, void *pParam)
78 {
79     prvI2C.IsBusy = 0;
80 }
81 
I2C_IrqHandle(int32_t IrqLine,void * pData)82 static void I2C_IrqHandle(int32_t IrqLine, void *pData)
83 {
84     int32_t result = ERROR_NONE;
85     I2C_TypeDef *I2C = prvI2C.RegBase;
86     uint32_t Source = I2C->IC_TX_ABRT_SOURCE;
87     uint32_t State = I2C->IC_RAW_INTR_STAT;
88     uint32_t RegValue = I2C->IC_CLR_INTR;
89 
90     if (Source & 0x0000ffff)
91     {
92         result = -ERROR_OPERATION_FAILED;
93         goto I2C_DONE;
94     }
95 
96     switch(prvI2C.State)
97     {
98     case I2C_STATE_WRITE_ADDRESS:
99     case I2C_STATE_WRITE_REG:
100     case I2C_STATE_WRITE_DATA:
101         if (State & I2C_IT_TXE)
102         {
103             if (prvI2C.DataBuf.Pos >= prvI2C.DataBuf.MaxLen)
104             {
105                 goto I2C_DONE;
106             }
107             else if ((prvI2C.DataBuf.MaxLen - prvI2C.DataBuf.Pos) > 1)
108             {
109                 I2C->IC_DATA_CMD = prvI2C.DataBuf.Data[prvI2C.DataBuf.Pos];
110             }
111             else
112             {
113                 I2C->IC_DATA_CMD = prvI2C.DataBuf.Data[prvI2C.DataBuf.Pos]|I2C_IC_DATA_CMD_STOP;
114             }
115             prvI2C.DataBuf.Pos++;
116         }
117         break;
118     case I2C_STATE_READ_ADDRESS_WR:
119         if (State & I2C_IT_TXE)
120         {
121             prvI2C.State = I2C_STATE_READ_ADDRESS_RD;
122             if ((prvI2C.DataBuf.MaxLen - prvI2C.DataBuf.Pos) > 1)
123             {
124                 I2C->IC_DATA_CMD = I2C_IC_DATA_CMD_CMD;
125             }
126             else
127             {
128                 I2C->IC_DATA_CMD = I2C_IC_DATA_CMD_CMD|I2C_IC_DATA_CMD_STOP;
129             }
130             I2C->IC_INTR_MASK = I2C_IC_INTR_MASK_M_RX_FULL|I2C_IC_INTR_MASK_M_STOP_DET;
131         }
132         break;
133     case I2C_STATE_READ_ADDRESS_RD:
134         prvI2C.State = I2C_STATE_READ_DATA_RD;
135     case I2C_STATE_READ_DATA_RD:
136         if (State & I2C_IT_RXF)
137         {
138             prvI2C.DataBuf.Data[prvI2C.DataBuf.Pos] = I2C->IC_DATA_CMD & 0x00ff;
139             prvI2C.DataBuf.Pos++;
140             if (prvI2C.DataBuf.Pos >= prvI2C.DataBuf.MaxLen)
141             {
142                 goto I2C_DONE;
143             }
144             else if ((prvI2C.DataBuf.MaxLen - prvI2C.DataBuf.Pos) > 1)
145             {
146                 I2C->IC_DATA_CMD = I2C_IC_DATA_CMD_CMD;
147             }
148             else
149             {
150                 I2C->IC_DATA_CMD = I2C_IC_DATA_CMD_CMD|I2C_IC_DATA_CMD_STOP;
151             }
152         }
153         break;
154     default:
155         break;
156     }
157     return;
158 I2C_DONE:
159     I2C->IC_INTR_MASK = 0;
160     prvI2C_Done(result);
161 }
162 
I2C_IrqHandleRegQueue(int32_t IrqLine,void * pData)163 static void I2C_IrqHandleRegQueue(int32_t IrqLine, void *pData)
164 {
165     int32_t result = ERROR_NONE;
166     I2C_TypeDef *I2C = prvI2C.RegBase;
167     uint32_t Source = I2C->IC_TX_ABRT_SOURCE;
168     uint32_t State = I2C->IC_RAW_INTR_STAT;
169     uint32_t RegValue = I2C->IC_CLR_INTR;
170 
171     if (Source & 0x0000ffff)
172     {
173 
174         result = -ERROR_OPERATION_FAILED;
175         goto I2C_DONE;
176     }
177 
178     if (State & I2C_IT_TXE)
179     {
180         if (prvI2C.DataBuf.Pos >= prvI2C.DataBuf.MaxLen)
181         {
182             prvI2C.CurQueuePos++;
183             if (prvI2C.CurQueuePos >= prvI2C.TotalQueueNum)
184             {
185                 goto I2C_DONE;
186             }
187             else
188             {
189                 Buffer_StaticInit(&prvI2C.DataBuf, prvI2C.RegQueue[prvI2C.CurQueuePos].Data, 2);
190                 I2C->IC_DATA_CMD = prvI2C.DataBuf.Data[0];
191                 prvI2C.DataBuf.Pos++;
192                 I2C->IC_INTR_MASK = I2C_IC_INTR_MASK_M_TX_EMPTY|I2C_IC_INTR_MASK_M_STOP_DET;
193             }
194 
195         }
196         else if ((prvI2C.DataBuf.MaxLen - prvI2C.DataBuf.Pos) > 1)
197         {
198             I2C->IC_DATA_CMD = prvI2C.DataBuf.Data[prvI2C.DataBuf.Pos];
199         }
200         else
201         {
202             I2C->IC_DATA_CMD = prvI2C.DataBuf.Data[prvI2C.DataBuf.Pos]|I2C_IC_DATA_CMD_STOP;
203         }
204         prvI2C.DataBuf.Pos++;
205     }
206     return;
207 I2C_DONE:
208     I2C->IC_INTR_MASK = 0;
209     prvI2C_Done(result);
210 }
211 
I2C_GlobalInit(void)212 void I2C_GlobalInit(void)
213 {
214     prvI2C.Callback = prvI2C_DummyCB;
215     ISR_SetHandler(prvI2C.IrqLine, I2C_IrqHandle, NULL);
216 #ifdef __BUILD_OS__
217     prvI2C.Sem = OS_MutexCreate();
218     ISR_SetPriority(prvI2C.IrqLine, configLIBRARY_LOWEST_INTERRUPT_PRIORITY - 1);
219 #else
220     ISR_SetPriority(prvI2C.IrqLine, 7);
221 #endif
222 }
223 
I2C_MasterSetup(uint8_t I2CID,uint32_t Speed)224 void I2C_MasterSetup(uint8_t I2CID, uint32_t Speed)
225 {
226     I2C_TypeDef *I2C = prvI2C.RegBase;
227     uint32_t Cnt = ((SystemCoreClock >> 3) / Speed);
228     I2C->IC_ENABLE = 0;
229     while(I2C->IC_ENABLE_STATUS & I2C_IC_ENABLE_STATUS_IC_EN){;}
230     I2C->IC_SDA_HOLD = 5;
231     I2C->IC_SDA_SETUP = Cnt/3;
232     switch(Speed)
233     {
234     case 100000:
235         I2C->IC_SS_SCL_HCNT = Cnt - I2C->IC_FS_SPKLEN;
236         I2C->IC_SS_SCL_LCNT = Cnt;
237         I2C->IC_CON = I2C_IC_CON_RESTART_EN|I2C_IC_CON_SPEED_0|I2C_IC_CON_MASTER_MODE|I2C_IC_CON_SLAVE_DISABLE;
238         break;
239     case 400000:
240         I2C->IC_FS_SCL_HCNT = Cnt - I2C->IC_FS_SPKLEN;
241         I2C->IC_FS_SCL_LCNT = Cnt;
242         I2C->IC_CON = I2C_IC_CON_RESTART_EN|I2C_IC_CON_SPEED_1|I2C_IC_CON_MASTER_MODE|I2C_IC_CON_SLAVE_DISABLE;
243         break;
244     }
245     I2C->IC_ENABLE = 1;
246     I2C->IC_RX_TL = 0;
247     I2C->IC_TX_TL = 0;
248     I2C->IC_INTR_MASK = 0;
249     return;
250 }
251 
I2C_Prepare(uint8_t I2CID,uint16_t ChipAddress,uint8_t ChipAddressLen,CBFuncEx_t CB,void * pParam)252 void I2C_Prepare(uint8_t I2CID, uint16_t ChipAddress, uint8_t ChipAddressLen, CBFuncEx_t CB, void *pParam)
253 {
254     I2C_TypeDef *I2C = prvI2C.RegBase;
255     I2C->IC_ENABLE = 0;
256     while(I2C->IC_ENABLE_STATUS & I2C_IC_ENABLE_STATUS_IC_EN){;}
257 
258     switch(ChipAddressLen)
259     {
260     case 1:
261         I2C->IC_TAR = ChipAddress & 0x00ff;
262         I2C->IC_SAR = ChipAddress & 0x00ff;
263         break;
264     case 2:
265         I2C->IC_TAR = I2C_IC_TAR_10BITADDR_MASTER | (ChipAddress & I2C_IC_TAR_TAR);
266         I2C->IC_SAR = ChipAddress;
267         break;
268     }
269     I2C->IC_ENABLE = 1;
270     if (CB)
271     {
272         prvI2C.Callback = CB;
273     }
274     else
275     {
276         prvI2C.Callback = prvI2C_DummyCB;
277     }
278     prvI2C.pParam = pParam;
279 }
280 
I2C_MasterXfer(uint8_t I2CID,uint8_t Operate,uint8_t RegAddress,uint8_t * Data,uint32_t Len,uint16_t Toms)281 void I2C_MasterXfer(uint8_t I2CID, uint8_t Operate, uint8_t RegAddress, uint8_t *Data, uint32_t Len, uint16_t Toms)
282 {
283     I2C_TypeDef *I2C = prvI2C.RegBase;
284     uint32_t RegValue;
285     I2C->IC_INTR_MASK = 0;
286     ISR_OnOff(prvI2C.IrqLine, 0);
287     if (prvI2C.IsBusy)
288     {
289         I2C->IC_ENABLE |= I2C_IC_ENABLE_ABORT;
290         prvI2C.IsBusy = 0;
291         prvI2C.Result = -ERROR_OPERATION_FAILED;
292         prvI2C.Callback(I2C_ID0, prvI2C.pParam);
293         while(I2C->IC_ENABLE & I2C_IC_ENABLE_ABORT){;}
294     }
295     ISR_SetHandler(prvI2C.IrqLine, I2C_IrqHandle, NULL);
296     prvI2C.IsBusy = 1;
297     if (Toms)
298     {
299         prvI2C.TimeoutMs = Toms;
300     }
301     else
302     {
303         prvI2C.TimeoutMs = 50;
304     }
305     Buffer_StaticInit(&prvI2C.DataBuf, Data, Len);
306     prvI2C.RegQueue = NULL;
307     RegValue = I2C->IC_CLR_INTR;
308     switch(Operate)
309     {
310     case I2C_OP_READ_REG:
311 
312         prvI2C.State = I2C_STATE_READ_ADDRESS_WR;
313         I2C->IC_DATA_CMD = I2C_IC_DATA_CMD_RESTART|RegAddress;
314         I2C->IC_INTR_MASK = I2C_IC_INTR_MASK_M_TX_EMPTY|I2C_IC_INTR_MASK_M_STOP_DET;
315         break;
316     case I2C_OP_READ:
317         prvI2C.State = I2C_STATE_READ_ADDRESS_RD;
318         if ((prvI2C.DataBuf.MaxLen - prvI2C.DataBuf.Pos) > 1)
319         {
320             I2C->IC_DATA_CMD = I2C_IC_DATA_CMD_CMD;
321         }
322         else
323         {
324             I2C->IC_DATA_CMD = I2C_IC_DATA_CMD_CMD|I2C_IC_DATA_CMD_STOP;
325         }
326         I2C->IC_INTR_MASK = I2C_IC_INTR_MASK_M_RX_FULL|I2C_IC_INTR_MASK_M_STOP_DET;
327         break;
328     case I2C_OP_WRITE:
329         prvI2C.State = I2C_STATE_WRITE_ADDRESS;
330         if ((prvI2C.DataBuf.MaxLen - prvI2C.DataBuf.Pos) > 1)
331         {
332             I2C->IC_DATA_CMD = prvI2C.DataBuf.Data[0];
333         }
334         else
335         {
336             I2C->IC_DATA_CMD = prvI2C.DataBuf.Data[0]|I2C_IC_DATA_CMD_STOP;
337         }
338         prvI2C.DataBuf.Pos++;
339         I2C->IC_INTR_MASK = I2C_IC_INTR_MASK_M_TX_EMPTY|I2C_IC_INTR_MASK_M_STOP_DET;
340         break;
341     default:
342         prvI2C.IsBusy = 0;
343         prvI2C.Result = -ERROR_PARAM_INVALID;
344         prvI2C.Callback(I2C_ID0, prvI2C.pParam);
345         return;
346     }
347 
348     ISR_OnOff(prvI2C.IrqLine, 1);
349 }
350 
I2C_MasterWriteRegQueue(uint8_t I2CID,I2C_CommonRegDataStruct * RegQueue,uint32_t TotalNum,uint16_t Toms,uint8_t IsBlock)351 int32_t I2C_MasterWriteRegQueue(uint8_t I2CID, I2C_CommonRegDataStruct *RegQueue, uint32_t TotalNum, uint16_t Toms, uint8_t IsBlock)
352 {
353     I2C_TypeDef *I2C = prvI2C.RegBase;
354     uint32_t RegValue;
355     int32_t Result;
356     I2C->IC_INTR_MASK = 0;
357     ISR_OnOff(prvI2C.IrqLine, 0);
358     if (prvI2C.IsBusy)
359     {
360         I2C->IC_ENABLE |= I2C_IC_ENABLE_ABORT;
361         prvI2C.IsBusy = 0;
362         prvI2C.Result = -ERROR_OPERATION_FAILED;
363         prvI2C.Callback(I2C_ID0, prvI2C.pParam);
364         while(I2C->IC_ENABLE & I2C_IC_ENABLE_ABORT){;}
365     }
366     ISR_SetHandler(prvI2C.IrqLine, I2C_IrqHandleRegQueue, NULL);
367     prvI2C.IsBusy = 1;
368     if (Toms)
369     {
370         prvI2C.TimeoutMs = Toms;
371     }
372     else
373     {
374         prvI2C.TimeoutMs = 50;
375     }
376     prvI2C.RegQueue = RegQueue;
377     prvI2C.TotalQueueNum = TotalNum;
378     prvI2C.CurQueuePos = 0;
379     RegValue = I2C->IC_CLR_INTR;
380     Buffer_StaticInit(&prvI2C.DataBuf, prvI2C.RegQueue[prvI2C.CurQueuePos].Data, 2);
381     I2C->IC_DATA_CMD = prvI2C.DataBuf.Data[0];
382     prvI2C.DataBuf.Pos++;
383     I2C->IC_INTR_MASK = I2C_IC_INTR_MASK_M_TX_EMPTY|I2C_IC_INTR_MASK_M_STOP_DET;
384     ISR_OnOff(prvI2C.IrqLine, 1);
385     if (IsBlock)
386     {
387         while(!I2C_WaitResult(I2CID, &Result)) {;}
388         return Result;
389     }
390     else
391     {
392         return 0;
393     }
394 }
395 
396 
I2C_WaitResult(uint8_t I2CID,int32_t * Result)397 int I2C_WaitResult(uint8_t I2CID, int32_t *Result)
398 {
399     if (prvI2C.IsBusy) return 0;
400     *Result = prvI2C.Result;
401     return 1;
402 }
403 
I2C_BlockWrite(uint8_t I2CID,uint8_t ChipAddress,const uint8_t * Data,uint32_t Len,uint16_t Toms,CBFuncEx_t CB,void * pParam)404 int32_t I2C_BlockWrite(uint8_t I2CID, uint8_t ChipAddress, const uint8_t *Data, uint32_t Len, uint16_t Toms, CBFuncEx_t CB, void *pParam)
405 {
406     int32_t Result;
407     while(!I2C_WaitResult(I2CID, &Result)) {;}
408     prvI2C.IsBlockMode = !OS_CheckInIrq();
409     I2C_Prepare(I2CID, ChipAddress, 1, CB, pParam);
410     I2C_MasterXfer(I2CID, I2C_OP_WRITE, 0, Data, Len, Toms);
411 #ifdef __BUILD_OS__
412     if (!OS_CheckInIrq())
413     {
414         OS_MutexLock(prvI2C.Sem);
415     }
416 #endif
417     while(!I2C_WaitResult(I2CID, &Result)) {;}
418     return Result;
419 }
420 
I2C_BlockRead(uint8_t I2CID,uint8_t ChipAddress,uint8_t * Reg,uint8_t * Data,uint32_t Len,uint16_t Toms,CBFuncEx_t CB,void * pParam)421 int32_t I2C_BlockRead(uint8_t I2CID, uint8_t ChipAddress, uint8_t *Reg, uint8_t *Data, uint32_t Len, uint16_t Toms, CBFuncEx_t CB, void *pParam)
422 {
423     int32_t Result;
424     while(!I2C_WaitResult(I2CID, &Result)) {;}
425     prvI2C.IsBlockMode = !OS_CheckInIrq();
426     I2C_Prepare(I2CID, ChipAddress, 1, CB, pParam);
427     if (Reg)
428     {
429         I2C_MasterXfer(I2CID, I2C_OP_READ_REG, *Reg, Data, Len, Toms);
430     }
431     else
432     {
433         I2C_MasterXfer(I2CID, I2C_OP_READ, 0, Data, Len, Toms);
434     }
435 #ifdef __BUILD_OS__
436     if (!OS_CheckInIrq())
437     {
438         OS_MutexLock(prvI2C.Sem);
439     }
440 #endif
441     while(!I2C_WaitResult(I2CID, &Result)) {;}
442     return Result;
443 }
444 
I2C_ForceStop(uint8_t I2CID)445 void I2C_ForceStop(uint8_t I2CID)
446 {
447     I2C_TypeDef *I2C = prvI2C.RegBase;
448     IIC_DBG("%d,%x",prvI2C.State, I2C->IC_RAW_INTR_STAT);
449     I2C->IC_ENABLE |= I2C_IC_ENABLE_ABORT;
450     I2C->IC_INTR_MASK = 0;
451     prvI2C_Done(-ERROR_TIMEOUT);
452     while(I2C->IC_ENABLE & I2C_IC_ENABLE_ABORT){;}
453 }
454