summaryrefslogtreecommitdiff
path: root/firmware/target/coldfire/iaudio/x5/pcf50606-x5.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/coldfire/iaudio/x5/pcf50606-x5.c')
-rw-r--r--firmware/target/coldfire/iaudio/x5/pcf50606-x5.c518
1 files changed, 4 insertions, 514 deletions
diff --git a/firmware/target/coldfire/iaudio/x5/pcf50606-x5.c b/firmware/target/coldfire/iaudio/x5/pcf50606-x5.c
index 59ecdb612c..58ff5d5cb0 100644
--- a/firmware/target/coldfire/iaudio/x5/pcf50606-x5.c
+++ b/firmware/target/coldfire/iaudio/x5/pcf50606-x5.c
@@ -17,515 +17,11 @@
17 * 17 *
18 ****************************************************************************/ 18 ****************************************************************************/
19#include "config.h" 19#include "config.h"
20#include "cpu.h"
21#include <stdbool.h>
22#include "kernel.h"
23#include "system.h" 20#include "system.h"
24#include "hwcompat.h" 21#include "kernel.h"
25#include "logf.h" 22#include "pcf50606.h"
26#include "debug.h"
27#include "string.h"
28#include "generic_i2c.h"
29#include "powermgmt.h" 23#include "powermgmt.h"
30 24
31#define USE_ASM
32
33/* Data */
34#define SDA_BITNUM 12 /* SDA1/RXD1/GPIO44 */
35#define SDA_GPIO_READ GPIO1_READ /* MBAR2 + 0x0b0 */
36#define SDA_GPIO_OUT GPIO1_OUT /* MBAR2 + 0x0b4 */
37#define SDA_GPIO_ENABLE GPIO1_ENABLE /* MBAR2 + 0x0b8 */
38#define SDA_GPIO_FUNCTION GPIO1_FUNCTION /* MBAR2 + 0x0bc */
39
40/* Clock */
41#define SCL_BITNUM 10 /* SCL1/TXD1/GPIO10 */
42#define SCL_GPIO_READ GPIO_READ /* MBAR2 + 0x000 */
43#define SCL_GPIO_OUT GPIO_OUT /* MBAR2 + 0x004 */
44#define SCL_GPIO_ENABLE GPIO_ENABLE /* MBAR2 + 0x008 */
45#define SCL_GPIO_FUNCTION GPIO_FUNCTION /* MBAR2 + 0x00c */
46
47#define PCF50606_ADDR 0x10
48#define SCL_BIT (1ul << SCL_BITNUM)
49#define SDA_BIT (1ul << SDA_BITNUM)
50
51#define SDA ( SDA_BIT & SDA_GPIO_READ)
52#define SDA_LO_OUT or_l( SDA_BIT, &SDA_GPIO_ENABLE)
53#define SDA_HI_IN and_l(~SDA_BIT, &SDA_GPIO_ENABLE)
54
55#define SCL ( SCL_BIT & SCL_GPIO_READ)
56#define SCL_LO_OUT or_l( SCL_BIT, &SCL_GPIO_ENABLE)
57#define SCL_HI_IN and_l(~SCL_BIT, &SCL_GPIO_ENABLE); while(!SCL);
58
59#define DELAY \
60 asm ( \
61 "move.l %[dly],%%d0 \n" \
62 "1: \n" \
63 "subq.l #1,%%d0 \n" \
64 "bhi.s 1b \n" \
65 : : [dly]"d"(i2c_delay) : "d0" );
66
67static int i2c_delay IDATA_ATTR = 44;
68
69void pcf50606_i2c_recalc_delay(int cpu_clock)
70{
71 i2c_delay = MAX(cpu_clock / (400000*2*3) - 7, 1);
72}
73
74inline void pcf50606_i2c_start(void)
75{
76#ifdef USE_ASM
77 asm (
78 "not.l %[sdab] \n" /* SDA_HI_IN */
79 "and.l %[sdab],(8,%[sdard]) \n"
80 "not.l %[sdab] \n"
81
82 "not.l %[sclb] \n" /* SCL_HI_IN */
83 "and.l %[sclb],(8,%[sclrd]) \n"
84 "not.l %[sclb] \n"
85 "1: \n"
86 "move.l (%[sclrd]),%%d0 \n"
87 "btst.l %[sclbnum], %%d0 \n"
88 "beq.s 1b \n"
89
90 "move.l %[dly],%%d0 \n" /* DELAY */
91 "1: \n"
92 "subq.l #1,%%d0 \n"
93 "bhi.s 1b \n"
94
95 "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */
96
97 "move.l %[dly],%%d0 \n" /* DELAY */
98 "1: \n"
99 "subq.l #1,%%d0 \n"
100 "bhi.s 1b \n"
101
102 "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */
103 : /* outputs */
104 : /* inputs */
105 [sclrd] "a"(&SCL_GPIO_READ),
106 [sclb] "d"(SCL_BIT),
107 [sclbnum] "i"(SCL_BITNUM),
108 [sdard] "a"(&SDA_GPIO_READ),
109 [sdab] "d"(SDA_BIT),
110 [dly] "d"(i2c_delay)
111 : /* clobbers */
112 "d0"
113 );
114#else
115 SDA_HI_IN;
116 SCL_HI_IN;
117 DELAY;
118 SDA_LO_OUT;
119 DELAY;
120 SCL_LO_OUT;
121#endif
122}
123
124inline void pcf50606_i2c_stop(void)
125{
126#ifdef USE_ASM
127 asm (
128 "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */
129
130 "not.l %[sclb] \n" /* SCL_HI_IN */
131 "and.l %[sclb],(8,%[sclrd]) \n"
132 "not.l %[sclb] \n"
133 "1: \n"
134 "move.l (%[sclrd]),%%d0 \n"
135 "btst.l %[sclbnum],%%d0 \n"
136 "beq.s 1b \n"
137
138 "move.l %[dly],%%d0 \n" /* DELAY */
139 "1: \n"
140 "subq.l #1,%%d0 \n"
141 "bhi.s 1b \n"
142
143 "not.l %[sdab] \n" /* SDA_HI_IN */
144 "and.l %[sdab],(8,%[sdard]) \n"
145 "not.l %[sdab] \n"
146 : /* outputs */
147 : /* inputs */
148 [sclrd] "a"(&SCL_GPIO_READ),
149 [sclb] "d"(SCL_BIT),
150 [sclbnum] "i"(SCL_BITNUM),
151 [sdard] "a"(&SDA_GPIO_READ),
152 [sdab] "d"(SDA_BIT),
153 [dly] "d"(i2c_delay)
154 : /* clobbers */
155 "d0"
156 );
157#else
158 SDA_LO_OUT;
159 SCL_HI_IN;
160 DELAY;
161 SDA_HI_IN;
162#endif
163}
164
165inline void pcf50606_i2c_ack(bool ack)
166{
167#ifdef USE_ASM
168 asm (
169 "tst.b %[ack] \n" /* if (!ack) */
170 "bne.s 1f \n"
171
172 "not.l %[sdab] \n" /* SDA_HI_IN */
173 "and.l %[sdab],(8,%[sdard]) \n"
174 "not.l %[sdab] \n"
175 ".word 0x51fb \n" /* trapf.l : else */
176 "1: \n"
177 "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */
178
179 "not.l %[sclb] \n" /* SCL_HI_IN */
180 "and.l %[sclb],(8,%[sclrd]) \n"
181 "not.l %[sclb] \n"
182 "1: \n"
183 "move.l (%[sclrd]),%%d0 \n"
184 "btst.l %[sclbnum],%%d0 \n"
185 "beq.s 1b \n"
186
187 "move.l %[dly],%%d0 \n" /* DELAY */
188 "1: \n"
189 "subq.l #1,%%d0 \n"
190 "bhi.s 1b \n"
191
192 "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */
193 : /* outputs */
194 : /* inputs */
195 [sclrd] "a"(&SCL_GPIO_READ),
196 [sclb] "d"(SCL_BIT),
197 [sclbnum] "i"(SCL_BITNUM),
198 [sdard] "a"(&SDA_GPIO_READ),
199 [sdab] "d"(SDA_BIT),
200 [dly] "d"(i2c_delay),
201 [ack] "d"(ack)
202 : /* clobbers */
203 "d0"
204 );
205#else
206 if(ack)
207 SDA_LO_OUT;
208 else
209 SDA_HI_IN;
210
211 SCL_HI_IN;
212
213 DELAY;
214 SCL_LO_OUT;
215#endif
216}
217
218inline bool pcf50606_i2c_getack(void)
219{
220 bool ret;
221
222#ifdef USE_ASM
223 asm (
224 "not.l %[sdab] \n" /* SDA_HI_IN */
225 "and.l %[sdab],(8,%[sdard]) \n"
226 "not.l %[sdab] \n"
227
228 "move.l %[dly],%%d0 \n" /* DELAY */
229 "1: \n"
230 "subq.l #1,%%d0 \n"
231 "bhi.s 1b \n"
232
233 "not.l %[sclb] \n" /* SCL_HI_IN */
234 "and.l %[sclb],(8,%[sclrd]) \n"
235 "not.l %[sclb] \n"
236 "1: \n"
237 "move.l (%[sclrd]),%%d0 \n"
238 "btst.l %[sclbnum],%%d0 \n"
239 "beq.s 1b \n"
240
241 "move.l (%[sdard]),%%d0 \n" /* ret = !SDA */
242 "btst.l %[sdabnum],%%d0 \n"
243 "seq.b %[ret] \n"
244
245 "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */
246
247 "move.l %[dly],%%d0 \n" /* DELAY */
248 "1: \n"
249 "subq.l #1,%%d0 \n"
250 "bhi.s 1b \n"
251 : /* outputs */
252 [ret] "=&d"(ret)
253 : /* inputs */
254 [sclrd] "a"(&SCL_GPIO_READ),
255 [sclb] "d"(SCL_BIT),
256 [sclbnum] "i"(SCL_BITNUM),
257 [sdard] "a"(&SDA_GPIO_READ),
258 [sdab] "d"(SDA_BIT),
259 [sdabnum] "i"(SDA_BITNUM),
260 [dly] "d"(i2c_delay)
261 : /* clobbers */
262 "d0"
263 );
264#else
265 SDA_HI_IN;
266 DELAY;
267 SCL_HI_IN;
268
269 ret = !SDA;
270
271 SCL_LO_OUT;
272 DELAY;
273#endif
274 return ret;
275}
276
277void pcf50606_i2c_outb(unsigned char byte)
278{
279#ifdef USE_ASM
280 asm volatile (
281 "moveq.l #24,%%d0 \n" /* byte <<= 24 */
282 "lsl.l %%d0,%[byte] \n"
283 "moveq.l #8,%%d1 \n" /* i = 8 */
284
285 "2: \n" /* do */
286 "lsl.l #1,%[byte] \n" /* if ((byte <<= 1) carry) */
287 "bcc.s 1f \n"
288
289 "not.l %[sdab] \n" /* SDA_HI_IN */
290 "and.l %[sdab],(8,%[sdard]) \n"
291 "not.l %[sdab] \n"
292 ".word 0x51fb \n" /* trapf.l; else */
293 "1: \n"
294 "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */
295
296 "move.l %[dly],%%d0 \n" /* DELAY */
297 "1: \n"
298 "subq.l #1,%%d0 \n"
299 "bhi.s 1b \n"
300
301 "not.l %[sclb] \n" /* SCL_HI_IN */
302 "and.l %[sclb],(8,%[sclrd]) \n"
303 "not.l %[sclb] \n"
304 "1: \n"
305 "move.l (%[sclrd]),%%d0 \n"
306 "btst.l %[sclbnum],%%d0 \n"
307 "beq.s 1b \n"
308
309 "move.l %[dly],%%d0 \n" /* DELAY */
310 "1: \n"
311 "subq.l #1,%%d0 \n"
312 "bhi.s 1b \n"
313
314 "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */
315
316 "subq.l #1,%%d1 \n" /* i-- */
317 "bne.s 2b \n" /* while (i != 0) */
318 : /* outputs */
319 [byte] "+d"(byte)
320 : /* inputs */
321 [sclrd] "a"(&SCL_GPIO_READ),
322 [sclb] "d"(SCL_BIT),
323 [sclbnum] "i"(SCL_BITNUM),
324 [sdard] "a"(&SDA_GPIO_READ),
325 [sdab] "d"(SDA_BIT),
326 [dly] "d"(i2c_delay)
327 : /* clobbers */
328 "d0", "d1"
329 );
330#else
331 int i;
332
333 /* clock out each bit, MSB first */
334 for ( i=0x80; i; i>>=1 )
335 {
336 if ( i & byte )
337 SDA_HI_IN;
338 else
339 SDA_LO_OUT;
340 DELAY;
341 SCL_HI_IN;
342 DELAY;
343 SCL_LO_OUT;
344 }
345#endif
346}
347
348unsigned char pcf50606_i2c_inb(bool ack)
349{
350 unsigned char byte = 0;
351
352#ifdef USE_ASM
353 asm (
354 "not.l %[sdab] \n" /* SDA_HI_IN */
355 "and.l %[sdab],(8,%[sdard]) \n"
356 "not.l %[sdab] \n"
357
358 "moveq.l #8,%%d1 \n" /* i = 8 */
359 "clr.l %[byte] \n" /* byte = 0 */
360
361 "2: \n" /* do */
362 "not.l %[sclb] \n" /* SCL_HI_IN */
363 "and.l %[sclb],(8,%[sclrd]) \n"
364 "not.l %[sclb] \n"
365 "1: \n"
366 "move.l (%[sclrd]),%%d0 \n"
367 "btst.l %[sclbnum],%%d0 \n"
368 "beq.s 1b \n"
369
370 "move.l %[dly],%%d0 \n" /* DELAY */
371 "1: \n"
372 "subq.l #1,%%d0 \n"
373 "bhi.s 1b \n"
374
375 "lsl.l #1,%[byte] \n" /* byte <<= 1 */
376 "move.l (%[sdard]),%%d0 \n" /* if (SDA) */
377 "btst.l %[sdabnum],%%d0 \n"
378 "beq.s 1f \n"
379 "addq.l #1,%[byte] \n" /* byte++ */
380 "1: \n"
381
382 "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */
383
384 "move.l %[dly],%%d0 \n" /* DELAY */
385 "1: \n"
386 "subq.l #1,%%d0 \n"
387 "bhi.s 1b \n"
388
389 "subq.l #1,%%d1 \n" /* i-- */
390 "bne.s 2b \n" /* while (i != 0) */
391 : /* outputs */
392 [byte] "=&d"(byte)
393 : /* inputs */
394 [sclrd] "a"(&SCL_GPIO_READ),
395 [sclb] "d"(SCL_BIT),
396 [sclbnum] "i"(SCL_BITNUM),
397 [sdard] "a"(&SDA_GPIO_READ),
398 [sdab] "d"(SDA_BIT),
399 [sdabnum] "i"(SDA_BITNUM),
400 [dly] "d"(i2c_delay)
401 : /* clobbers */
402 "d0", "d1"
403 );
404#else
405 int i;
406
407 /* clock in each bit, MSB first */
408 SDA_HI_IN;
409 for ( i=0x80; i; i>>=1 )
410 {
411 SCL_HI_IN;
412 DELAY;
413 if ( SDA )
414 byte |= i;
415 SCL_LO_OUT;
416 DELAY;
417 }
418#endif
419
420 pcf50606_i2c_ack(ack);
421
422 return byte;
423}
424
425int pcf50606_i2c_write(int address, const unsigned char* buf, int count)
426{
427 int i,x=0;
428
429 pcf50606_i2c_start();
430 pcf50606_i2c_outb(address & 0xfe);
431 if (pcf50606_i2c_getack())
432 {
433 for (i=0; i<count; i++)
434 {
435 pcf50606_i2c_outb(buf[i]);
436 if (!pcf50606_i2c_getack())
437 {
438 x=-2;
439 break;
440 }
441 }
442 }
443 else
444 {
445 logf("pcf50606_i2c_write() - no ack\n");
446 x=-1;
447 }
448 return x;
449}
450
451int pcf50606_read_multiple(int address, unsigned char* buf, int count)
452{
453 int i=0;
454 int ret = 0;
455 unsigned char obuf[1];
456
457 obuf[0] = address;
458
459 /* send read command */
460 if (pcf50606_i2c_write(PCF50606_ADDR, obuf, 1) >= 0)
461 {
462 pcf50606_i2c_start();
463 pcf50606_i2c_outb(0x11);
464 if (pcf50606_i2c_getack())
465 {
466 for(i = 0;i < count-1;i++)
467 buf[i] = pcf50606_i2c_inb(true);
468
469 buf[i] = pcf50606_i2c_inb(false);
470 }
471 else
472 {
473 ret = -1;
474 }
475 }
476
477 pcf50606_i2c_stop();
478
479 return ret;
480}
481
482int pcf50606_read(int address)
483{
484 int ret;
485 unsigned char c;
486
487 ret = pcf50606_read_multiple(address, &c, 1);
488 if(ret >= 0)
489 return c;
490 else
491 return ret;
492}
493
494int pcf50606_write_multiple(int address, const unsigned char* buf, int count)
495{
496 unsigned char obuf[1];
497 int i;
498 int ret = 0;
499
500 obuf[0] = address;
501
502 /* send write command */
503 if (pcf50606_i2c_write(PCF50606_ADDR, obuf, 1) >= 0)
504 {
505 for (i=0; i<count; i++)
506 {
507 pcf50606_i2c_outb(buf[i]);
508 if (!pcf50606_i2c_getack())
509 {
510 ret = -2;
511 break;
512 }
513 }
514 }
515 else
516 {
517 ret = -1;
518 }
519
520 pcf50606_i2c_stop();
521 return ret;
522}
523
524int pcf50606_write(int address, unsigned char val)
525{
526 return pcf50606_write_multiple(address, &val, 1);
527}
528
529/* These voltages were determined by measuring the output of the PCF50606 25/* These voltages were determined by measuring the output of the PCF50606
530 on a running X5, and verified by disassembling the original firmware */ 26 on a running X5, and verified by disassembling the original firmware */
531static void set_voltages(void) 27static void set_voltages(void)
@@ -572,13 +68,7 @@ static inline void enable_pmu_interrupts(void)
572 68
573void pcf50606_init(void) 69void pcf50606_init(void)
574{ 70{
575 /* Bit banged I2C */ 71 pcf50606_i2c_init();
576 or_l(SDA_BIT, &SDA_GPIO_FUNCTION);
577 or_l(SCL_BIT, &SCL_GPIO_FUNCTION);
578 and_l(~SDA_BIT, &SDA_GPIO_OUT);
579 and_l(~SCL_BIT, &SCL_GPIO_OUT);
580 and_l(~SDA_BIT, &SDA_GPIO_ENABLE);
581 and_l(~SCL_BIT, &SCL_GPIO_ENABLE);
582 72
583 /* initialize pmu interrupts but don't service them yet */ 73 /* initialize pmu interrupts but don't service them yet */
584 init_pmu_interrupts(); 74 init_pmu_interrupts();
@@ -611,7 +101,7 @@ void pcf50606_reset_timeout(void)
611void GPI0(void) __attribute__ ((interrupt_handler, section(".text"))); 101void GPI0(void) __attribute__ ((interrupt_handler, section(".text")));
612void GPI0(void) 102void GPI0(void)
613{ 103{
614 char read[3]; /* 0 = INT1, 1 = INT2, 2 = INT3 */ 104 unsigned char read[3]; /* 0 = INT1, 1 = INT2, 2 = INT3 */
615 105
616 /* clear pending interrupts from pcf50606 */ 106 /* clear pending interrupts from pcf50606 */
617 pcf50606_read_multiple(0x02, read, 3); 107 pcf50606_read_multiple(0x02, read, 3);