• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Winner Microelectronics Co., Ltd. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 /****************************************************************************
17  * @file     wm_i2c.c
18  * @author
19  * @version
20  * @date
21  * @brief
22  *
23  * Copyright (c) 2014 Winner Microelectronics Co., Ltd. All rights reserved.
24  *****************************************************************************/
25 
26 #include "wm_i2c.h"
27 #include "stddef.h"
28 
29 #define I2C_FREQ_MAX            (400000)
30 #define I2C_FREQ_MIN            (100000)
31 #define I2C_WRITE                (0x80)
32 #define I2C_READ                (0x00)
33 typedef struct {
34     uint8_t addr;
35     uint8_t dev_addr;
36     uint8_t state;
37     uint8_t *buf;
38     uint16_t len;
39     uint16_t cnt;
40     uint8_t cmd;
41     void (*transfer_done)(void);
42 } i2c_desc;
43 enum {
44     START,
45     RESTART,
46     TRANSMIT,
47     PRERECEIVE,
48     RECEIVE,
49     STOP,
50     DONE,
51     IDLE,
52 };
53 static i2c_desc i2c_transfer;
54 
i2c_I2C_IRQHandler(void)55 ATTRIBUTE_ISR void i2c_I2C_IRQHandler(void)
56 {
57     int i2c_sr;
58     csi_kernel_intrpt_enter();
59     i2c_sr = I2C->CR_SR;
60     I2C->CR_SR = 1;
61     if (i2c_sr & 0x20) {
62         printf("I2C AL lost\r\n");
63     }
64     if (i2c_sr & 0x01) {
65         if ((i2c_sr & 0x80) == 0) {
66             switch (i2c_transfer.state) {
67                 case START:
68                     I2C->TX_RX = i2c_transfer.addr;
69                     I2C->CR_SR = I2C_CR_WR;
70                     if ((i2c_transfer.cmd & I2C_WRITE) == I2C_WRITE) {
71                         i2c_transfer.state = TRANSMIT;
72                     } else {
73                         i2c_transfer.state = RESTART;
74                     }
75                     break;
76 
77                 case RESTART:
78                     I2C->TX_RX = (i2c_transfer.dev_addr | 0x01);
79                     I2C->CR_SR = (I2C_CR_STA | I2C_CR_WR);
80                     i2c_transfer.state = PRERECEIVE;
81                     break;
82 
83                 case TRANSMIT:
84                     I2C->TX_RX = i2c_transfer.buf[i2c_transfer.cnt++];
85                     I2C->CR_SR = I2C_CR_WR;
86                     if (i2c_transfer.cnt == i2c_transfer.len) {
87                         i2c_transfer.state = STOP;
88                     }
89                     break;
90 
91                 case PRERECEIVE:
92                     i2c_transfer.state = RECEIVE;
93                     I2C->CR_SR = I2C_CR_RD;
94                     break;
95                 case RECEIVE:
96                     i2c_transfer.buf[i2c_transfer.cnt++] = I2C->TX_RX;
97                     if (i2c_transfer.cnt == (i2c_transfer.len - 1)) {
98                         I2C->CR_SR = (I2C_CR_STO | I2C_CR_NAK | I2C_CR_RD);
99                         i2c_transfer.state = STOP;
100                     } else if (i2c_transfer.len == 1) {
101                         I2C->CR_SR = (I2C_CR_STO | I2C_CR_NAK | I2C_CR_RD);
102                         i2c_transfer.state = DONE;
103                         if (i2c_transfer.transfer_done) {
104                             i2c_transfer.transfer_done();
105                         }
106                     } else {
107                         I2C->CR_SR = I2C_CR_RD;
108                     }
109                     break;
110 
111                 case STOP:
112                     I2C->CR_SR = I2C_CR_STO;
113                     i2c_transfer.state = DONE;
114                     if (i2c_transfer.transfer_done) {
115                         i2c_transfer.transfer_done();
116                     }
117                     break;
118             }
119         } else {
120             if ((i2c_transfer.state == STOP) && i2c_transfer.cmd != I2C_WRITE) {
121                 i2c_transfer.buf[i2c_transfer.cnt] = I2C->TX_RX;
122                 i2c_transfer.state = DONE;
123                 if (i2c_transfer.transfer_done) {
124                     i2c_transfer.transfer_done();
125                 }
126             }
127         }
128     }
129     csi_kernel_intrpt_exit();
130 }
131 
tls_i2c_init(u32 freq)132 void tls_i2c_init(u32 freq)
133 {
134     u32 div = 0;
135     tls_sys_clk clk;
136 
137     if (freq < I2C_FREQ_MIN) {
138         freq = I2C_FREQ_MIN;
139     } else if (freq > I2C_FREQ_MAX) {
140         freq = I2C_FREQ_MAX;
141     }
142     tls_sys_clk_get(&clk);
143 
144     div = (clk.apbclk * 1000000)/(5 * freq) - 1;
145     tls_reg_write32(HR_I2C_PRER_LO, div & 0xff);
146     tls_reg_write32(HR_I2C_PRER_HI, (div>>8) & 0xff);
147 
148     /** enable I2C | Disable Int*/
149     tls_reg_write32(HR_I2C_CTRL, I2C_CTRL_INT_DISABLE | I2C_CTRL_ENABLE);
150     tls_irq_enable(I2C_IRQn);
151 }
152 
153 /**
154  * @brief    send stop signal
155  *
156  */
tls_i2c_stop(void)157 void tls_i2c_stop(void)
158 {
159     tls_reg_write32(HR_I2C_CR_SR, I2C_CR_STO);
160     while (tls_reg_read32(HR_I2C_CR_SR) & I2C_SR_TIP);
161 }
162 
163 /**
164  * @brief    waiting for ack signal
165  * @retval
166  *    - \ref WM_FAILED
167  *    - \ref WM_SUCCESS
168  */
tls_i2c_wait_ack(void)169 int tls_i2c_wait_ack(void)
170 {
171     u16 errtime = 0;
172     u32 value;
173 
174     while (tls_reg_read32(HR_I2C_CR_SR) & I2C_SR_TIP);
175     value = tls_reg_read32(HR_I2C_CR_SR);
176     while (value & I2C_SR_NAK) {
177         errtime ++;
178         if (errtime > 512) {
179             printf("wait ack err\n");
180             tls_i2c_stop();
181             return WM_FAILED;
182         }
183         value = tls_reg_read32(HR_I2C_CR_SR);
184     }
185 
186     return WM_SUCCESS;
187 }
188 
189 /**
190  * @brief    writes the data to data register of I2C module
191  * when \ifstart one the start signal will be sent followed by the \data
192  * when \ifstart zero only the \data will be send
193  * @param[in] data    the data will be write to the data register of I2C module
194  * @param[in] ifstart    when one send start signal, when zero don't
195  * @retval
196  *
197  */
tls_i2c_write_byte(u8 data,u8 ifstart)198 void tls_i2c_write_byte(u8 data, u8 ifstart)
199 {
200     tls_reg_write32(HR_I2C_TX_RX, data);
201     if (ifstart)
202         tls_reg_write32(HR_I2C_CR_SR, I2C_CR_STA | I2C_CR_WR);
203     else
204         tls_reg_write32(HR_I2C_CR_SR, I2C_CR_WR);
205     while (tls_reg_read32(HR_I2C_CR_SR) & I2C_SR_TIP);
206 }
207 
208 /**
209  * @brief    get the data stored in data register of I2C module
210  * @param[in] ifack    when one send ack after reading the data register,when zero don't
211  * @param[in] ifstop when one send stop signal after read, when zero do not send stop
212  * @retval    the received data
213  */
tls_i2c_read_byte(u8 ifack,u8 ifstop)214 u8 tls_i2c_read_byte(u8 ifack, u8 ifstop)
215 {
216     u8 data;
217     u32 value = I2C_CR_RD;
218 
219     if (!ifack)
220         value |= I2C_CR_NAK;
221     if (ifstop)
222         value |= I2C_CR_STO;
223 
224     tls_reg_write32(HR_I2C_CR_SR, value);
225     /** Waiting finish */
226     while (tls_reg_read32(HR_I2C_CR_SR) & I2C_SR_TIP);
227     data = tls_reg_read32(HR_I2C_TX_RX);
228 
229     return data;
230 }
231 
232 /**
233  * @brief    start write through int mode
234  * @param[in] devaddr    the device address
235  * @param[in] wordaddr when one send stop signal after read, when zero do not send stop
236  * @param[in] buf    the address point where data shoule be stored
237  * @param[in] len    the length of data will be received
238  * @retval
239  *    - \ref WM_FAILED
240  *    - \ref WM_SUCCESS
241  */
wm_i2c_start_write_it(uint8_t devaddr,uint8_t wordaddr,uint8_t * buf,uint16_t len)242 int wm_i2c_start_write_it(uint8_t devaddr, uint8_t wordaddr, uint8_t * buf, uint16_t len)
243 {
244     if (buf == NULL) {
245         return WM_FAILED;
246     }
247     I2C->TX_RX = devaddr;
248     i2c_transfer.dev_addr = devaddr;
249     i2c_transfer.state = START;
250     i2c_transfer.cmd = I2C_WRITE;
251     i2c_transfer.buf = buf;
252     i2c_transfer.len = len;
253     i2c_transfer.cnt = 0;
254     i2c_transfer.addr = wordaddr;
255     I2C->CR_SR = I2C_CR_STA | I2C_CR_WR;
256     return WM_SUCCESS;
257 }
258 
259 /**
260  * @brief    start read through int mode
261  * @param[in] devaddr    the device address
262  * @param[in] wordaddr when one send stop signal after read, when zero do not send stop
263  * @param[in] buf    the address point where data shoule be stored
264  * @param[in] len    the length of data will be received
265  * @retval
266  *    - \ref WM_FAILED
267  *    - \ref WM_SUCCESS
268  */
wm_i2c_start_read_it(uint8_t devaddr,uint8_t wordaddr,uint8_t * buf,uint16_t len)269 int wm_i2c_start_read_it(uint8_t devaddr, uint8_t wordaddr, uint8_t * buf, uint16_t len)
270 {
271     if (buf == NULL) {
272         return WM_FAILED;
273     }
274     I2C->TX_RX = devaddr;
275     i2c_transfer.dev_addr = devaddr;
276     i2c_transfer.state = START;
277     i2c_transfer.cmd = I2C_READ;
278     i2c_transfer.buf = buf;
279     i2c_transfer.len = len;
280     i2c_transfer.cnt = 0;
281     i2c_transfer.addr = wordaddr;
282     I2C->CR_SR = I2C_CR_STA | I2C_CR_WR;
283 
284     return WM_SUCCESS;
285 }
286 
287 /**
288  * @brief          This function is used to register i2c transfer done callback function.
289  * @param[in]      done  is the i2c transfer done callback function.
290  * @retval         None
291  * @note           None
292  */
wm_i2c_transfer_done_register(void (* done)(void))293 void wm_i2c_transfer_done_register(void (*done)(void))
294 {
295     i2c_transfer.transfer_done = done;
296 }
297 
298 /*** (C) COPYRIGHT 2014 Winner Microelectronics Co., Ltd. ***/
299