summaryrefslogtreecommitdiff
path: root/firmware/target/mips/ingenic_jz47xx/i2c-jz4760.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/mips/ingenic_jz47xx/i2c-jz4760.c')
-rw-r--r--firmware/target/mips/ingenic_jz47xx/i2c-jz4760.c355
1 files changed, 355 insertions, 0 deletions
diff --git a/firmware/target/mips/ingenic_jz47xx/i2c-jz4760.c b/firmware/target/mips/ingenic_jz47xx/i2c-jz4760.c
new file mode 100644
index 0000000000..e35fe7a091
--- /dev/null
+++ b/firmware/target/mips/ingenic_jz47xx/i2c-jz4760.c
@@ -0,0 +1,355 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2016 by Roman Stolyarov
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "config.h"
22#include "system.h"
23#include "cpu.h"
24#include "logf.h"
25#include "i2c.h"
26
27#define I2C_CHN 1
28#define I2C_CLK 100000
29
30#define I2C_READ 1
31#define I2C_WRITE 0
32
33#define I2C_M_RD 1
34#define I2C_M_WR 2
35
36#define TIMEOUT 100000
37
38static char i2c_rwflags;
39static int i2c_ctrl_rest = 0;
40static unsigned char *msg_buf;
41static int cmd_cnt;
42static volatile int cmd_flag;
43static int r_cnt;
44static unsigned char i2c_subaddr = 0;
45
46/*
47 * I2C bus protocol basic routines
48 */
49
50/* Interrupt handler */
51void I2C1(void)
52{
53 int timeout = TIMEOUT;
54
55 if (__i2c_abrt_7b_addr_nack(I2C_CHN)) {
56 int ret;
57 cmd_flag = -1;
58 __i2c_clear_interrupts(ret,I2C_CHN);
59 REG_I2C_INTM(I2C_CHN) = 0x0;
60 return;
61 }
62
63 /* first byte,when length > 1 */
64 if (cmd_flag == 0 && cmd_cnt > 1) {
65 cmd_flag = 1;
66 if (i2c_rwflags == I2C_M_RD) {
67 REG_I2C_DC(I2C_CHN) = I2C_READ << 8;
68 } else {
69 REG_I2C_DC(I2C_CHN) = (I2C_WRITE << 8) | *msg_buf++;
70 }
71 cmd_cnt--;
72 }
73
74 if (i2c_rwflags == I2C_M_RD) {
75 if (REG_I2C_STA(I2C_CHN) & I2C_STA_RFNE) {
76 *msg_buf++ = REG_I2C_DC(I2C_CHN) & 0xff;
77 r_cnt--;
78 }
79
80 REG_I2C_DC(I2C_CHN) = I2C_READ << 8;
81 } else {
82 REG_I2C_DC(I2C_CHN) = (I2C_WRITE << 8) | *msg_buf++;
83 }
84
85 cmd_cnt--;
86
87 if (!(cmd_cnt)) {
88 REG_I2C_INTM(I2C_CHN) = 0x0;
89 cmd_flag = 2;
90 if (i2c_rwflags == I2C_M_RD){
91 while (r_cnt > 2) {
92 if ((REG_I2C_STA(I2C_CHN) & I2C_STA_RFNE) && timeout) {
93 *msg_buf++ = REG_I2C_DC(I2C_CHN) & 0xff;
94 r_cnt--;
95 }
96 if (!(timeout--)) {
97 cmd_flag = -1;
98 return;
99 }
100 }
101 }
102 }
103
104 return;
105}
106
107static int i2c_set_clk(int i2c_clk)
108{
109 int dev_clk = __cpm_get_pclk();
110 int count = 0;
111
112 if (i2c_clk < 0 || i2c_clk > 400000)
113 goto Set_clk_err;
114
115 count = dev_clk/i2c_clk - 23;
116 if (count < 0)
117 goto Set_clk_err;
118
119 if (i2c_clk <= 100000) {
120 REG_I2C_CTRL(I2C_CHN) = 0x43 | i2c_ctrl_rest; /* standard speed mode*/
121 if (count%2 == 0) {
122 REG_I2C_SHCNT(I2C_CHN) = count/2 + 6 - 5;
123 REG_I2C_SLCNT(I2C_CHN) = count/2 + 8 + 5;
124 } else {
125 REG_I2C_SHCNT(I2C_CHN) = count/2 + 6 -5;
126 REG_I2C_SLCNT(I2C_CHN) = count/2 + 8 +5 + 1;
127 }
128 } else {
129 REG_I2C_CTRL(I2C_CHN) = 0x45 | i2c_ctrl_rest; /* high speed mode*/
130 if (count%2 == 0) {
131 REG_I2C_FHCNT(I2C_CHN) = count/2 + 6;
132 REG_I2C_FLCNT(I2C_CHN) = count/2 + 8;
133 } else {
134 REG_I2C_FHCNT(I2C_CHN) = count/2 + 6;
135 REG_I2C_FLCNT(I2C_CHN) = count/2 + 8 + 1;
136 }
137 }
138 return 0;
139
140Set_clk_err:
141
142 logf("i2c set sclk faild,i2c_clk=%d,dev_clk=%d.\n",i2c_clk,dev_clk);
143 return -1;
144}
145
146static int i2c_disable(void)
147{
148 int timeout = TIMEOUT;
149
150 __i2c_disable(I2C_CHN);
151 while(__i2c_is_enable(I2C_CHN) && (timeout > 0)) {
152 udelay(1);
153 timeout--;
154 }
155 if(timeout)
156 return 0;
157 else
158 return 1;
159}
160
161static int i2c_enable(void)
162{
163 int timeout = TIMEOUT;
164
165 __i2c_enable(I2C_CHN);
166 while(__i2c_is_disable(I2C_CHN) && (timeout > 0)) {
167 udelay(1);
168 timeout--;
169 }
170 if(timeout)
171 return 0;
172 else
173 return 1;
174}
175
176static void i2c_init_as_master(unsigned char address)
177{
178 if(i2c_disable())
179 logf("i2c not disable\n");
180
181 i2c_set_clk(I2C_CLK);
182
183 REG_I2C_TAR(I2C_CHN) = address; /* slave id needed write only once */
184 REG_I2C_INTM(I2C_CHN) = 0x0; /* unmask all interrupts */
185 REG_I2C_TXTL(I2C_CHN) = 0x1;
186
187 if(i2c_enable())
188 logf("i2c not enable\n");
189}
190
191int xfer_read_subaddr(unsigned char subaddr, unsigned char device, unsigned char *buf, int length)
192{
193 int timeout,r_i = 0;
194
195 cmd_cnt = length;
196 r_cnt = length;
197 msg_buf = buf;
198 i2c_rwflags = I2C_M_RD;
199 i2c_ctrl_rest = I2C_CTRL_REST;
200 i2c_init_as_master(device);
201
202 REG_I2C_DC(I2C_CHN) = (I2C_WRITE << 8) | subaddr;
203
204 cmd_flag = 0;
205 REG_I2C_INTM(I2C_CHN) = 0x10;
206 timeout = TIMEOUT;
207 while (cmd_flag != 2 && --timeout) {
208 if (cmd_flag == -1) {
209 r_i = 1;
210 goto R_dev_err;
211 }
212 udelay(10);
213 }
214 if (!timeout) {
215 r_i = 4;
216 goto R_timeout;
217 }
218
219 while (r_cnt) {
220 while (!(REG_I2C_STA(I2C_CHN) & I2C_STA_RFNE)) {
221 if ((cmd_flag == -1) ||
222 (REG_I2C_INTST(I2C_CHN) & I2C_INTST_TXABT) ||
223 REG_I2C_TXABRT(I2C_CHN)) {
224 int ret;
225 r_i = 2;
226 __i2c_clear_interrupts(ret,I2C_CHN);
227 goto R_dev_err;
228 }
229 }
230 *msg_buf++ = REG_I2C_DC(I2C_CHN) & 0xff;
231 r_cnt--;
232 }
233
234 timeout = TIMEOUT;
235 while ((REG_I2C_STA(I2C_CHN) & I2C_STA_MSTACT) && --timeout)
236 udelay(10);
237 if (!timeout){
238 r_i = 3;
239 goto R_timeout;
240 }
241
242 return 0;
243
244R_dev_err:
245R_timeout:
246
247 i2c_init_as_master(device);
248 if (r_i == 1) {
249 logf("Read i2c device 0x%2x failed in r_i = %d :device no ack.\n",device,r_i);
250 } else if (r_i == 2) {
251 logf("Read i2c device 0x%2x failed in r_i = %d :i2c abort.\n",device,r_i);
252 } else if (r_i == 3) {
253 logf("Read i2c device 0x%2x failed in r_i = %d :waite master inactive timeout.\n",device,r_i);
254 } else if (r_i == 4) {
255 logf("Read i2c device 0x%2x failed in r_i = %d.\n",device,r_i);
256 } else {
257 logf("Read i2c device 0x%2x failed in r_i = %d.\n",device,r_i);
258 }
259 return -1;
260}
261
262int xfer_write_subaddr(unsigned char subaddr, unsigned char device, const unsigned char *buf, int length)
263{
264 int timeout,w_i = 0;
265
266 cmd_cnt = length;
267 r_cnt = length;
268 msg_buf = (unsigned char *)buf;
269 i2c_rwflags = I2C_M_WR;
270 i2c_ctrl_rest = I2C_CTRL_REST;
271 i2c_init_as_master(device);
272
273 REG_I2C_DC(I2C_CHN) = (I2C_WRITE << 8) | subaddr;
274
275 cmd_flag = 0;
276 REG_I2C_INTM(I2C_CHN) = 0x10;
277
278 timeout = TIMEOUT;
279 while ((cmd_flag != 2) && (--timeout))
280 {
281 if (cmd_flag == -1){
282 w_i = 1;
283 goto W_dev_err;
284 }
285 udelay(10);
286 }
287
288 timeout = TIMEOUT;
289 while((!(REG_I2C_STA(I2C_CHN) & I2C_STA_TFE)) && --timeout){
290 udelay(10);
291 }
292 if (!timeout){
293 w_i = 2;
294 goto W_timeout;
295 }
296
297 timeout = TIMEOUT;
298 while (__i2c_master_active(I2C_CHN) && --timeout);
299 if (!timeout){
300 w_i = 3;
301 goto W_timeout;
302 }
303
304 if ((length == 1)&&
305 ((cmd_flag == -1) ||
306 (REG_I2C_INTST(I2C_CHN) & I2C_INTST_TXABT) ||
307 REG_I2C_TXABRT(I2C_CHN))) {
308 int ret;
309 w_i = 5;
310 __i2c_clear_interrupts(ret,I2C_CHN);
311 goto W_dev_err;
312 }
313
314 return 0;
315
316W_dev_err:
317W_timeout:
318
319 i2c_init_as_master(device);
320 if (w_i == 1) {
321 logf("Write i2c device 0x%2x failed in w_i=%d:device no ack. I2C_CHN:[%d]sxyzhang\n",device,w_i,I2C_CHN);
322 } else if (w_i == 2) {
323 logf("Write i2c device 0x%2x failed in w_i=%d:waite TF buff empty timeout.\n",device,w_i);
324 } else if (w_i == 3) {
325 logf("Write i2c device 0x%2x failed in w_i=%d:waite master inactive timeout.\n",device,w_i);
326 } else if (w_i == 5) {
327 logf("Write i2c device 0x%2x failed in w_i=%d:device no ack or abort.I2C_CHN:[%d]sxyzhang \n",device,w_i,I2C_CHN);
328 } else {
329 logf("Write i2c device 0x%2x failed in w_i=%d.\n",device,w_i);
330 }
331
332 return -1;
333}
334
335int i2c_read(int device, unsigned char* buf, int count)
336{
337 return xfer_read_subaddr(i2c_subaddr, device, &buf[0], count);
338}
339
340int i2c_write(int device, const unsigned char* buf, int count)
341{
342 if (count < 2)
343 {
344 i2c_subaddr = buf[0];
345 return 0;
346 }
347 return xfer_write_subaddr(buf[0], device, &buf[1], count-1);
348}
349
350void i2c_init(void)
351{
352 __gpio_as_i2c(I2C_CHN);
353 __cpm_start_i2c1();
354 system_enable_irq(IRQ_I2C1);
355}