1 /**
2     *****************************************************************************
3     * @file     cmem7_i2c.c
4     *
5     * @brief    CMEM7 I2C source file
6     *
7     *
8     * @version  V1.0
9     * @date     3. September 2013
10     *
11     * @note
12     *
13     *****************************************************************************
14     * @attention
15     *
16     * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
17     * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
18     * TIME. AS A RESULT, CAPITAL-MICRO SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
19     * INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
20     * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
21     * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
22     *
23     * <h2><center>&copy; COPYRIGHT 2013 Capital-micro </center></h2>
24     *****************************************************************************
25     */
26 
27 #include "cmem7_i2c.h"
28 
29 #define I2C_INNER_INT_ALL               0x3FF
30 
31 typedef struct {
32     union {
33     uint32_t  DATA_CMD;
34 
35     struct {
36       uint32_t  DATA       :  8;
37       uint32_t  RD_CMD     :  1;
38       uint32_t  WR_CMD     :  1;
39       uint32_t  WR_RD_CMD  :  1;
40     } DATA_CMD_b;
41   } INNER;
42 } I2C_INNER_DATA_CMD;
43 
i2c_GetClock(I2C0_Type * I2Cx)44 static uint32_t i2c_GetClock(I2C0_Type* I2Cx) {
45     uint32_t dividor;
46     assert_param(IS_I2C_ALL_PERIPH(I2Cx));
47 
48     if ((uint32_t)I2Cx == (uint32_t)I2C0) {
49         dividor = GLOBAL_CTRL->CLK_SEL_0_b.I2C0_CLK;
50     } else if ((uint32_t)I2Cx == (uint32_t)I2C1) {
51         dividor = GLOBAL_CTRL->CLK_SEL_0_b.I2C1_CLK;
52     }
53 
54     return SYSTEM_CLOCK_FREQ / (1 << (dividor + 1));
55 }
56 
i2c_NormalizeAddr(I2C0_Type * I2Cx,uint16_t addr)57 static uint16_t i2c_NormalizeAddr(I2C0_Type* I2Cx, uint16_t addr) {
58     assert_param(IS_I2C_ALL_PERIPH(I2Cx));
59 
60     if (I2Cx->CTRL_b.MODE == I2C_Mode_Master) {
61         if (I2Cx->CTRL_b.MASTER_ADDR_WIDTH == I2C_ADDR_WIDTH_7BIT) {
62             addr &= 0x007F;
63         } else {
64             addr &= 0x3FF;
65         }
66     }
67 
68     if (I2Cx->CTRL_b.MODE == I2C_Mode_Slave) {
69         if (I2Cx->CTRL_b.SLAVE_ADDR_WIDTH == I2C_ADDR_WIDTH_7BIT) {
70             addr &= 0x007F;
71         } else {
72             addr &= 0x3FF;
73         }
74     }
75 
76     return addr;
77 }
78 
i2c_ReadClear(uint32_t bit)79 static void i2c_ReadClear(uint32_t bit) {
80     uint32_t tmp;
81     tmp = bit;
82     tmp = tmp;
83 }
84 
I2C_Init(I2C0_Type * I2Cx,I2C_InitTypeDef * I2C_Init)85 void I2C_Init(I2C0_Type* I2Cx, I2C_InitTypeDef* I2C_Init) {
86     assert_param(IS_I2C_ALL_PERIPH(I2Cx));
87     assert_param(I2C_Init);
88     assert_param(IS_I2C_MODE(I2C_Init->I2C_Mode));
89     assert_param(IS_I2C_ADDR_WIDTH(I2C_Init->I2C_AddressWidth));
90 
91     // reset
92     I2Cx->ENABLE_b.RESET = FALSE;
93     I2Cx->ENABLE_b.RESET = TRUE;
94 
95     // clear interrupt
96     I2Cx->INT_MASK = I2C_INNER_INT_ALL;
97     i2c_ReadClear(I2Cx->CLR_ALL_INT_b.CLEAR);
98 
99     I2Cx->CTRL_b.MODE = I2C_Init->I2C_Mode;
100     if (I2Cx->CTRL_b.MODE == I2C_Mode_Master) {
101         I2Cx->CTRL_b.MASTER_ADDR_WIDTH = I2C_Init->I2C_AddressWidth;
102         I2Cx->TAR_b.START_BYTE = TRUE;
103         I2Cx->TAR_b.ADDR10 = i2c_NormalizeAddr(I2Cx, I2C_Init->I2C_Address);
104     }
105     if (I2Cx->CTRL_b.MODE == I2C_Mode_Slave) {
106         I2Cx->CTRL_b.SLAVE_ADDR_WIDTH = I2C_Init->I2C_AddressWidth;
107         I2Cx->SAR_b.ADDR10 = i2c_NormalizeAddr(I2Cx, I2C_Init->I2C_Address);
108     }
109 
110     I2Cx->RX_TL_b.THRESHOLD = 0;
111     I2Cx->TX_TL_b.THRESHOLD = 0;
112 
113     I2Cx->SLAVE_NACK_b.NACK = FALSE;
114 
115     if (I2C_Init->timing) {
116         I2Cx->SCL_CNT_b.HIGH_LEVEL_TICK =
117           i2c_GetClock(I2Cx) / I2C_Init->timing->I2C_Freq / 2;
118         I2Cx->SCL_CNT_b.LOW_LEVEL_TICK =
119           i2c_GetClock(I2Cx) / I2C_Init->timing->I2C_Freq / 2;
120         I2Cx->SDA_SETUP_b.TSU_DAT = ((uint64_t)I2C_Init->timing->I2C_TsuDat) *
121           i2c_GetClock(I2Cx) / 1000000000;
122         I2Cx->SDA_SETUP_b.TSETUP = ((uint64_t)I2C_Init->timing->I2C_Tsetup) *
123           i2c_GetClock(I2Cx) / 1000000000;
124         I2Cx->TSU_STA_SETUP_b.TBUF = ((uint64_t)I2C_Init->timing->I2C_Tbuf) *
125           i2c_GetClock(I2Cx) / 1000000000;
126         I2Cx->TSU_STA_SETUP_b.TSU_STA = ((uint64_t)I2C_Init->timing->I2C_TsuSta) *
127           i2c_GetClock(I2Cx) / 1000000000;
128         I2Cx->TSU_STA_SETUP_b.SDA_FILTER_EN = I2C_Init->timing->I2C_SdaFilterEn;
129         I2Cx->TSU_STA_SETUP_b.SDA_FILTER_CNT = I2C_Init->timing->I2C_SdaFilterSpike;
130         I2Cx->TSU_STA_SETUP_b.SCL_FILTER_EN = I2C_Init->timing->I2C_SclFilterEn;
131         I2Cx->TSU_STA_SETUP_b.SCL_FILTER_CNT = I2C_Init->timing->I2C_SclFilterSpike;
132   }
133 }
134 
I2C_Enable(I2C0_Type * I2Cx,BOOL enable)135 void I2C_Enable(I2C0_Type* I2Cx, BOOL enable) {
136     assert_param(IS_I2C_ALL_PERIPH(I2Cx));
137 
138     I2Cx->ENABLE_b.EN = enable;
139 }
140 
I2C_EnableInt(I2C0_Type * I2Cx,uint32_t Int,BOOL enable)141 void I2C_EnableInt(I2C0_Type* I2Cx, uint32_t Int, BOOL enable) {
142     assert_param(IS_I2C_ALL_PERIPH(I2Cx));
143     assert_param(IS_I2C_INT(Int));
144 
145     if (enable) {
146       I2Cx->INT_MASK &= ~Int;
147     } else {
148         I2Cx->INT_MASK |= Int;
149     }
150 }
151 
I2C_GetIntStatus(I2C0_Type * I2Cx,uint32_t Int)152 BOOL I2C_GetIntStatus(I2C0_Type* I2Cx, uint32_t Int) {
153     assert_param(IS_I2C_ALL_PERIPH(I2Cx));
154     assert_param(IS_I2C_INT(Int));
155 
156     if (0 != (I2Cx->INT_STATUS & Int)) {
157         return TRUE;
158     }
159 
160     return FALSE;
161 }
I2C_ClearInt(I2C0_Type * I2Cx,uint32_t Int)162 void I2C_ClearInt(I2C0_Type* I2Cx, uint32_t Int) {
163     assert_param(IS_I2C_ALL_PERIPH(I2Cx));
164     assert_param(IS_I2C_INT(Int));
165 
166     if (Int == I2C_INT_RX_FIFO_NOT_EMPTY) {
167         // It can't be clear by sw but read data
168     }
169 
170     if (Int == I2C_INT_RD_REQUEST) {
171         i2c_ReadClear(I2Cx->CLR_RD_REQ_b.CLEAR);
172     }
173 
174     if (Int == I2C_INT_TX_ABORT) {
175         i2c_ReadClear(I2Cx->CLR_TX_ABRT_b.CLEAR);
176     }
177 
178     if (Int == I2C_INT_RX_DONE) {
179         i2c_ReadClear(I2Cx->CLR_RX_DONE_b.CLEAR);
180     }
181 
182     if (Int == I2C_INT_TX_DONE) {
183         i2c_ReadClear(I2Cx->CLR_TX_DONE_b.CLEAR);
184     }
185 }
186 
I2C_GetStatus(I2C0_Type * I2Cx,uint32_t Status)187 BOOL I2C_GetStatus(I2C0_Type* I2Cx, uint32_t Status) {
188     assert_param(IS_I2C_ALL_PERIPH(I2Cx));
189     assert_param(IS_I2C_STATUS(Status));
190 
191     if (0 != (I2Cx->STATUS & Status)) {
192         return TRUE;
193     }
194 
195     return FALSE;
196 }
197 
I2C_ClearStatus(I2C0_Type * I2Cx,uint32_t Status)198 void I2C_ClearStatus(I2C0_Type* I2Cx, uint32_t Status) {
199     assert_param(IS_I2C_ALL_PERIPH(I2Cx));
200     assert_param(IS_I2C_STATUS(Status));
201 
202     if (Status & I2C_STATUS_RX_FIFO_NOT_EMPTY) {
203         // It can't be clear by sw but read
204     }
205 
206     if (Status & I2C_STATUS_RD_REQUEST) {
207         i2c_ReadClear(I2Cx->CLR_RD_REQ_b.CLEAR);
208     }
209 
210     if (Status & I2C_STATUS_TX_ABORT) {
211         i2c_ReadClear(I2Cx->CLR_TX_ABRT_b.CLEAR);
212     }
213 
214     if (Status & I2C_STATUS_RX_DONE) {
215         i2c_ReadClear(I2Cx->CLR_RX_DONE_b.CLEAR);
216     }
217 
218     if (Status & I2C_STATUS_TX_DONE) {
219         i2c_ReadClear(I2Cx->CLR_TX_DONE_b.CLEAR);
220     }
221 }
222 
I2C_MasterReadReq(I2C0_Type * I2Cx,uint8_t size)223 BOOL I2C_MasterReadReq(I2C0_Type* I2Cx, uint8_t size) {
224     assert_param(IS_I2C_ALL_PERIPH(I2Cx));
225 
226     if (!I2Cx->ENABLE_b.EN || I2Cx->STATUS_b.BUSY) {
227         return FALSE;
228     }
229 
230     if (I2Cx->CTRL_b.MODE == I2C_Mode_Slave) {
231       return FALSE;
232     }
233 
234     if (size == 0) {
235         return FALSE;
236     }
237 
238     I2Cx->WRITE_READ_CNT_b.RD_BYTE_CNT = size;
239     if (size != 0) {
240     I2C_INNER_DATA_CMD inner;
241 
242     inner.INNER.DATA_CMD_b.DATA = 0;
243         inner.INNER.DATA_CMD_b.RD_CMD = TRUE;
244         inner.INNER.DATA_CMD_b.WR_CMD = FALSE;
245         inner.INNER.DATA_CMD_b.WR_RD_CMD = FALSE;
246 
247         I2Cx->DATA_CMD = inner.INNER.DATA_CMD;
248     }
249 
250     return TRUE;
251 }
252 
I2C_ReadFifo(I2C0_Type * I2Cx,uint8_t size,uint8_t * data)253 uint8_t I2C_ReadFifo(I2C0_Type* I2Cx, uint8_t size, uint8_t* data) {
254     uint8_t count;
255 
256     assert_param(IS_I2C_ALL_PERIPH(I2Cx));
257     assert_param(data);
258 
259     if (!I2Cx->ENABLE_b.EN) {
260         return 0;
261     }
262 
263     count = 0;
264     while (I2Cx->STATUS_b.RX_FIFO_NOT_EMPTY && count < size) {
265         *(data + count++) = I2Cx->DATA_CMD_b.DATA;
266     }
267 
268     return count;
269 }
270 
I2C_WriteReq(I2C0_Type * I2Cx,uint8_t size,uint8_t firstData)271 BOOL I2C_WriteReq(I2C0_Type* I2Cx, uint8_t size, uint8_t firstData) {
272     assert_param(IS_I2C_ALL_PERIPH(I2Cx));
273 
274     if (!I2Cx->ENABLE_b.EN || I2Cx->STATUS_b.BUSY) {
275         return FALSE;
276     }
277 
278     if (size == 0) {
279         return FALSE;
280     }
281 
282     I2Cx->WRITE_READ_CNT_b.WR_BYTE_CNT = size;
283     if (size != 0) {
284     I2C_INNER_DATA_CMD inner;
285 
286     inner.INNER.DATA_CMD_b.DATA = firstData ;
287         inner.INNER.DATA_CMD_b.RD_CMD = FALSE;
288         inner.INNER.DATA_CMD_b.WR_CMD =
289           (I2Cx->CTRL_b.MODE == I2C_Mode_Slave) ? FALSE : TRUE;
290         inner.INNER.DATA_CMD_b.WR_RD_CMD = FALSE;
291 
292         I2Cx->DATA_CMD = inner.INNER.DATA_CMD;
293     }
294 
295     return TRUE;
296 }
297 
I2C_WriteFifo(I2C0_Type * I2Cx,uint8_t size,uint8_t * data)298 uint8_t I2C_WriteFifo(I2C0_Type* I2Cx, uint8_t size, uint8_t* data) {
299     uint8_t count;
300 
301     assert_param(IS_I2C_ALL_PERIPH(I2Cx));
302     assert_param(data);
303 
304     if (!I2Cx->ENABLE_b.EN) {
305         return 0;
306     }
307 
308     count = 0;
309     while (I2Cx->STATUS_b.TX_FIFO_NOT_FULL && count < size) {
310       I2Cx->DATA_CMD_b.DATA = *(data + count++);
311     }
312 
313     return count;
314 }
315 
I2C_StopReq(I2C0_Type * I2Cx)316 BOOL I2C_StopReq(I2C0_Type* I2Cx) {
317     assert_param(IS_I2C_ALL_PERIPH(I2Cx));
318 
319     udelay(600);
320 
321     return TRUE;
322 }
323