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