diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2018-06-28 06:24:26 -0400 |
---|---|---|
committer | Michael Giacomelli <giac2000@hotmail.com> | 2018-07-28 10:56:31 -0400 |
commit | 0662793ca0050e823cd1207cc4689a1cba5068bd (patch) | |
tree | 08cd2ec59c9044c96b697b5bf8d0640841d044e0 /firmware/target/mips/ingenic_jz47xx/i2c-jz4760.c | |
parent | b3e2bd619b1b7ea94ef29d32db48e80b347a1990 (diff) | |
download | rockbox-0662793ca0050e823cd1207cc4689a1cba5068bd.tar.gz rockbox-0662793ca0050e823cd1207cc4689a1cba5068bd.zip |
Add cleaned-up xDuoo X3 support
Cleaned up, rebased, and forward-ported from the xvortex fork.
(original credit to vsoftster@gmail.com)
Change-Id: Ibcc023a0271ea81e901450a88317708c2683236d
Signed-off-by: Solomon Peachy <pizza@shaftnet.org>
Diffstat (limited to 'firmware/target/mips/ingenic_jz47xx/i2c-jz4760.c')
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/i2c-jz4760.c | 355 |
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 | |||
38 | static char i2c_rwflags; | ||
39 | static int i2c_ctrl_rest = 0; | ||
40 | static unsigned char *msg_buf; | ||
41 | static int cmd_cnt; | ||
42 | static volatile int cmd_flag; | ||
43 | static int r_cnt; | ||
44 | static unsigned char i2c_subaddr = 0; | ||
45 | |||
46 | /* | ||
47 | * I2C bus protocol basic routines | ||
48 | */ | ||
49 | |||
50 | /* Interrupt handler */ | ||
51 | void 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 | |||
107 | static 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 | |||
140 | Set_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 | |||
146 | static 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 | |||
161 | static 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 | |||
176 | static 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 | |||
191 | int 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 | |||
244 | R_dev_err: | ||
245 | R_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 | |||
262 | int 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 | |||
316 | W_dev_err: | ||
317 | W_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 | |||
335 | int i2c_read(int device, unsigned char* buf, int count) | ||
336 | { | ||
337 | return xfer_read_subaddr(i2c_subaddr, device, &buf[0], count); | ||
338 | } | ||
339 | |||
340 | int 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 | |||
350 | void i2c_init(void) | ||
351 | { | ||
352 | __gpio_as_i2c(I2C_CHN); | ||
353 | __cpm_start_i2c1(); | ||
354 | system_enable_irq(IRQ_I2C1); | ||
355 | } | ||