diff options
Diffstat (limited to 'firmware/drivers')
-rw-r--r-- | firmware/drivers/pcf50606.c | 418 |
1 files changed, 334 insertions, 84 deletions
diff --git a/firmware/drivers/pcf50606.c b/firmware/drivers/pcf50606.c index 51cd812346..5c8f8d0e96 100644 --- a/firmware/drivers/pcf50606.c +++ b/firmware/drivers/pcf50606.c | |||
@@ -27,123 +27,373 @@ | |||
27 | 27 | ||
28 | /* TODO: merge all bit-banged I2C into a generic I2C driver */ | 28 | /* TODO: merge all bit-banged I2C into a generic I2C driver */ |
29 | 29 | ||
30 | #define USE_ASM | ||
30 | 31 | ||
31 | #define SDA_LO and_l(~0x00002000, &GPIO1_OUT) | ||
32 | #define SDA_HI or_l( 0x00002000, &GPIO1_OUT) | ||
33 | #define SDA_INPUT and_l(~0x00002000, &GPIO1_ENABLE) | ||
34 | #define SDA_OUTPUT or_l( 0x00002000, &GPIO1_ENABLE) | ||
35 | #define SDA ( 0x00002000 & GPIO1_READ) | 32 | #define SDA ( 0x00002000 & GPIO1_READ) |
33 | #define SDA_LO_OUT or_l( 0x00002000, &GPIO1_ENABLE) | ||
34 | #define SDA_HI_IN and_l(~0x00002000, &GPIO1_ENABLE) | ||
36 | 35 | ||
37 | /* SCL is GPIO, 3 */ | ||
38 | #define SCL_INPUT and_l(~0x00001000, &GPIO_ENABLE) | ||
39 | #define SCL_OUTPUT or_l( 0x00001000, &GPIO_ENABLE) | ||
40 | #define SCL_LO and_l(~0x00001000, &GPIO_OUT) | ||
41 | #define SCL_HI SCL_INPUT;while(!SCL){};or_l(0x1000, &GPIO_OUT);SCL_OUTPUT | ||
42 | #define SCL ( 0x00001000 & GPIO_READ) | 36 | #define SCL ( 0x00001000 & GPIO_READ) |
37 | #define SCL_LO_OUT or_l( 0x00001000, &GPIO_ENABLE) | ||
38 | #define SCL_HI_IN and_l(~0x00001000, &GPIO_ENABLE); while(!SCL); | ||
43 | 39 | ||
44 | /* delay loop to achieve 400kHz at 120MHz CPU frequency */ | 40 | #define DELAY \ |
45 | #define DELAY do { int _x; for(_x=0;_x<22;_x++);} while(0) | 41 | asm ( \ |
42 | "move.l %[dly],%%d0 \n" \ | ||
43 | "1: \n" \ | ||
44 | "subq.l #1,%%d0 \n" \ | ||
45 | "bhi.s 1b \n" \ | ||
46 | : : [dly]"d"(i2c_delay) : "d0" ); | ||
46 | 47 | ||
47 | static void pcf50606_i2c_start(void) | 48 | static int i2c_delay IDATA_ATTR = 44; |
49 | |||
50 | void pcf50606_i2c_recalc_delay(int cpu_clock) | ||
48 | { | 51 | { |
49 | SDA_OUTPUT; | 52 | i2c_delay = MAX(cpu_clock / (400000*2*3) - 7, 1); |
50 | SCL_OUTPUT; | 53 | } |
51 | SDA_HI; | 54 | |
52 | SCL_HI; | 55 | static inline void pcf50606_i2c_start(void) |
56 | { | ||
57 | #ifdef USE_ASM | ||
58 | asm ( | ||
59 | "not.l %[sdab] \n" /* SDA_HI_IN */ | ||
60 | "and.l %[sdab],(8,%[gpi1]) \n" | ||
61 | "not.l %[sdab] \n" | ||
62 | |||
63 | "not.l %[sclb] \n" /* SCL_HI_IN */ | ||
64 | "and.l %[sclb],(8,%[gpio]) \n" | ||
65 | "not.l %[sclb] \n" | ||
66 | "1: \n" | ||
67 | "move.l (%[gpio]),%%d0 \n" | ||
68 | "btst.l #12,%%d0 \n" | ||
69 | "beq.s 1b \n" | ||
70 | |||
71 | "move.l %[dly],%%d0 \n" /* DELAY */ | ||
72 | "1: \n" | ||
73 | "subq.l #1,%%d0 \n" | ||
74 | "bhi.s 1b \n" | ||
75 | |||
76 | "or.l %[sdab],(8,%[gpi1]) \n" /* SDA_LO_OUT */ | ||
77 | |||
78 | "move.l %[dly],%%d0 \n" /* DELAY */ | ||
79 | "1: \n" | ||
80 | "subq.l #1,%%d0 \n" | ||
81 | "bhi.s 1b \n" | ||
82 | |||
83 | "or.l %[sclb],(8,%[gpio]) \n" /* SCL_LO_OUT */ | ||
84 | : /* outputs */ | ||
85 | : /* inputs */ | ||
86 | [gpio]"a"(&GPIO_READ), | ||
87 | [sclb]"d"(0x00001000), | ||
88 | [gpi1]"a"(&GPIO1_READ), | ||
89 | [sdab]"d"(0x00002000), | ||
90 | [dly] "d"(i2c_delay) | ||
91 | : /* clobbers */ | ||
92 | "d0" | ||
93 | ); | ||
94 | #else | ||
95 | SDA_HI_IN; | ||
96 | SCL_HI_IN; | ||
53 | DELAY; | 97 | DELAY; |
54 | SDA_LO; | 98 | SDA_LO_OUT; |
55 | DELAY; | 99 | DELAY; |
56 | SCL_LO; | 100 | SCL_LO_OUT; |
101 | #endif | ||
57 | } | 102 | } |
58 | 103 | ||
59 | static void pcf50606_i2c_stop(void) | 104 | static inline void pcf50606_i2c_stop(void) |
60 | { | 105 | { |
61 | SDA_LO; | 106 | #ifdef USE_ASM |
62 | SCL_HI; | 107 | asm ( |
63 | DELAY; | 108 | "or.l %[sdab],(8,%[gpi1]) \n" /* SDA_LO_OUT */ |
64 | SDA_HI; | 109 | |
110 | "not.l %[sclb] \n" /* SCL_HI_IN */ | ||
111 | "and.l %[sclb],(8,%[gpio]) \n" | ||
112 | "not.l %[sclb] \n" | ||
113 | "1: \n" | ||
114 | "move.l (%[gpio]),%%d0 \n" | ||
115 | "btst.l #12,%%d0 \n" | ||
116 | "beq.s 1b \n" | ||
117 | |||
118 | "move.l %[dly],%%d0 \n" /* DELAY */ | ||
119 | "1: \n" | ||
120 | "subq.l #1,%%d0 \n" | ||
121 | "bhi.s 1b \n" | ||
122 | |||
123 | "not.l %[sdab] \n" /* SDA_HI_IN */ | ||
124 | "and.l %[sdab],(8,%[gpi1]) \n" | ||
125 | "not.l %[sdab] \n" | ||
126 | : /* outputs */ | ||
127 | : /* inputs */ | ||
128 | [gpio]"a"(&GPIO_READ), | ||
129 | [sclb]"d"(0x00001000), | ||
130 | [gpi1]"a"(&GPIO1_READ), | ||
131 | [sdab]"d"(0x00002000), | ||
132 | [dly] "d"(i2c_delay) | ||
133 | : /* clobbers */ | ||
134 | "d0" | ||
135 | ); | ||
136 | #else | ||
137 | SDA_LO_OUT; | ||
138 | SCL_HI_IN; | ||
139 | DELAY; | ||
140 | SDA_HI_IN; | ||
141 | #endif | ||
65 | } | 142 | } |
66 | 143 | ||
67 | 144 | static inline void pcf50606_i2c_ack(bool ack) | |
68 | static void pcf50606_i2c_ack(bool ack) | ||
69 | { | 145 | { |
70 | SCL_LO; /* Set the clock low */ | 146 | #ifdef USE_ASM |
147 | asm ( | ||
148 | "tst.b %[ack] \n" /* if (!ack) */ | ||
149 | "bne.s 1f \n" | ||
150 | |||
151 | "not.l %[sdab] \n" /* SDA_HI_IN */ | ||
152 | "and.l %[sdab],(8,%[gpi1]) \n" | ||
153 | "not.l %[sdab] \n" | ||
154 | ".word 0x51fb \n" /* trapf.l : else */ | ||
155 | "1: \n" | ||
156 | "or.l %[sdab],(8,%[gpi1]) \n" /* SDA_LO_OUT */ | ||
157 | |||
158 | "not.l %[sclb] \n" /* SCL_HI_IN */ | ||
159 | "and.l %[sclb],(8,%[gpio]) \n" | ||
160 | "not.l %[sclb] \n" | ||
161 | "1: \n" | ||
162 | "move.l (%[gpio]),%%d0 \n" | ||
163 | "btst.l #12,%%d0 \n" | ||
164 | "beq.s 1b \n" | ||
165 | |||
166 | "move.l %[dly],%%d0 \n" /* DELAY */ | ||
167 | "1: \n" | ||
168 | "subq.l #1,%%d0 \n" | ||
169 | "bhi.s 1b \n" | ||
170 | |||
171 | "or.l %[sclb],(8,%[gpio]) \n" /* SCL_LO_OUT */ | ||
172 | : /* outputs */ | ||
173 | : /* inputs */ | ||
174 | [gpio]"a"(&GPIO_READ), | ||
175 | [sclb]"d"(0x00001000), | ||
176 | [gpi1]"a"(&GPIO1_READ), | ||
177 | [sdab]"d"(0x00002000), | ||
178 | [dly] "d"(i2c_delay), | ||
179 | [ack] "d"(ack) | ||
180 | : /* clobbers */ | ||
181 | "d0" | ||
182 | ); | ||
183 | #else | ||
71 | if(ack) | 184 | if(ack) |
72 | SDA_LO; | 185 | SDA_LO_OUT; |
73 | else | 186 | else |
74 | SDA_HI; | 187 | SDA_HI_IN; |
75 | 188 | ||
76 | SCL_HI; | 189 | SCL_HI_IN; |
77 | 190 | ||
78 | DELAY; | 191 | DELAY; |
79 | SCL_OUTPUT; | 192 | SCL_LO_OUT; |
80 | SCL_LO; | 193 | #endif |
81 | } | 194 | } |
82 | 195 | ||
83 | static int pcf50606_i2c_getack(void) | 196 | static inline bool pcf50606_i2c_getack(void) |
84 | { | 197 | { |
85 | int ret = 1; | 198 | bool ret; |
86 | 199 | ||
87 | SDA_INPUT; /* And set to input */ | 200 | #ifdef USE_ASM |
201 | asm ( | ||
202 | "not.l %[sdab] \n" /* SDA_HI_IN */ | ||
203 | "and.l %[sdab],(8,%[gpi1]) \n" | ||
204 | "not.l %[sdab] \n" | ||
205 | |||
206 | "move.l %[dly],%%d0 \n" /* DELAY */ | ||
207 | "1: \n" | ||
208 | "subq.l #1,%%d0 \n" | ||
209 | "bhi.s 1b \n" | ||
210 | |||
211 | "not.l %[sclb] \n" /* SCL_HI_IN */ | ||
212 | "and.l %[sclb],(8,%[gpio]) \n" | ||
213 | "not.l %[sclb] \n" | ||
214 | "1: \n" | ||
215 | "move.l (%[gpio]),%%d0 \n" | ||
216 | "btst.l #12,%%d0 \n" | ||
217 | "beq.s 1b \n" | ||
218 | |||
219 | "move.l (%[gpi1]),%%d0 \n" /* ret = !SDA */ | ||
220 | "btst.l #13,%%d0 \n" | ||
221 | "seq.b %[ret] \n" | ||
222 | |||
223 | "or.l %[sclb],(8,%[gpio]) \n" /* SCL_LO_OUT */ | ||
224 | |||
225 | "move.l %[dly],%%d0 \n" /* DELAY */ | ||
226 | "1: \n" | ||
227 | "subq.l #1,%%d0 \n" | ||
228 | "bhi.s 1b \n" | ||
229 | : /* outputs */ | ||
230 | [ret]"=&r"(ret) | ||
231 | : /* inputs */ | ||
232 | [gpio]"a"(&GPIO_READ), | ||
233 | [sclb]"d"(0x00001000), | ||
234 | [gpi1]"a"(&GPIO1_READ), | ||
235 | [sdab]"d"(0x00002000), | ||
236 | [dly] "d"(i2c_delay) | ||
237 | : /* clobbers */ | ||
238 | "d0" | ||
239 | ); | ||
240 | #else | ||
241 | SDA_HI_IN; | ||
88 | DELAY; | 242 | DELAY; |
89 | SCL_HI; | 243 | SCL_HI_IN; |
90 | 244 | ||
91 | if (SDA) | 245 | ret = !SDA; |
92 | /* ack failed */ | 246 | |
93 | ret = 0; | 247 | SCL_LO_OUT; |
94 | |||
95 | SCL_OUTPUT; | ||
96 | SCL_LO; | ||
97 | SDA_HI; | ||
98 | SDA_OUTPUT; | ||
99 | DELAY; | 248 | DELAY; |
249 | #endif | ||
100 | 250 | ||
101 | return ret; | 251 | return ret; |
102 | } | 252 | } |
103 | 253 | ||
104 | static void pcf50606_i2c_outb(unsigned char byte) | 254 | static void pcf50606_i2c_outb(unsigned char byte) |
105 | { | 255 | { |
106 | int i; | 256 | #ifdef USE_ASM |
107 | 257 | asm volatile ( | |
108 | /* clock out each bit, MSB first */ | 258 | "moveq.l #24,%%d0 \n" /* byte <<= 24 */ |
109 | for ( i=0x80; i; i>>=1 ) { | 259 | "lsl.l %%d0,%[byte] \n" |
110 | if ( i & byte ) | 260 | "moveq.l #8,%%d1 \n" /* i = 8 */ |
111 | { | 261 | |
112 | SDA_HI; | 262 | "2: \n" /* do */ |
113 | } | 263 | "lsl.l #1,%[byte] \n" /* if ((byte <<= 1) carry) */ |
114 | else | 264 | "bcc.s 1f \n" |
115 | { | 265 | |
116 | SDA_LO; | 266 | "not.l %[sdab] \n" /* SDA_HI_IN */ |
117 | } | 267 | "and.l %[sdab],(8,%[gpi1]) \n" |
118 | DELAY; | 268 | "not.l %[sdab] \n" |
119 | SCL_HI; | 269 | ".word 0x51fb \n" /* trapf.l; else */ |
120 | DELAY; | 270 | "1: \n" |
121 | SCL_LO; | 271 | "or.l %[sdab],(8,%[gpi1]) \n" /* SDA_LO_OUT */ |
122 | } | 272 | |
123 | 273 | "move.l %[dly],%%d0 \n" /* DELAY */ | |
124 | SDA_HI; | 274 | "1: \n" |
275 | "subq.l #1,%%d0 \n" | ||
276 | "bhi.s 1b \n" | ||
277 | |||
278 | "not.l %[sclb] \n" /* SCL_HI_IN */ | ||
279 | "and.l %[sclb],(8,%[gpio]) \n" | ||
280 | "not.l %[sclb] \n" | ||
281 | "1: \n" | ||
282 | "move.l (%[gpio]),%%d0 \n" | ||
283 | "btst.l #12,%%d0 \n" | ||
284 | "beq.s 1b \n" | ||
285 | |||
286 | "move.l %[dly],%%d0 \n" /* DELAY */ | ||
287 | "1: \n" | ||
288 | "subq.l #1,%%d0 \n" | ||
289 | "bhi.s 1b \n" | ||
290 | |||
291 | "or.l %[sclb],(8,%[gpio]) \n" /* SCL_LO_OUT */ | ||
292 | |||
293 | "subq.l #1,%%d1 \n" /* i-- */ | ||
294 | "bne.s 2b \n" /* while (i != 0) */ | ||
295 | : /* outputs */ | ||
296 | [byte]"+d"(byte) | ||
297 | : /* inputs */ | ||
298 | [gpio]"a"(&GPIO_READ), | ||
299 | [sclb]"d"(0x00001000), | ||
300 | [gpi1]"a"(&GPIO1_READ), | ||
301 | [sdab]"d"(0x00002000), | ||
302 | [dly] "d"(i2c_delay) | ||
303 | : /* clobbers */ | ||
304 | "d0", "d1" | ||
305 | ); | ||
306 | #else | ||
307 | int i; | ||
308 | |||
309 | /* clock out each bit, MSB first */ | ||
310 | for ( i=0x80; i; i>>=1 ) | ||
311 | { | ||
312 | if ( i & byte ) | ||
313 | SDA_HI_IN; | ||
314 | else | ||
315 | SDA_LO_OUT; | ||
316 | DELAY; | ||
317 | SCL_HI_IN; | ||
318 | DELAY; | ||
319 | SCL_LO_OUT; | ||
320 | } | ||
321 | #endif | ||
125 | } | 322 | } |
126 | 323 | ||
127 | static unsigned char pcf50606_i2c_inb(bool ack) | 324 | static unsigned char pcf50606_i2c_inb(bool ack) |
128 | { | 325 | { |
129 | int i; | 326 | unsigned char byte = 0; |
130 | unsigned char byte = 0; | 327 | |
131 | 328 | #ifdef USE_ASM | |
132 | /* clock in each bit, MSB first */ | 329 | asm ( |
133 | for ( i=0x80; i; i>>=1 ) { | 330 | "not.l %[sdab] \n" /* SDA_HI_IN */ |
134 | SDA_INPUT; /* And set to input */ | 331 | "and.l %[sdab],(8,%[gpi1]) \n" |
135 | SCL_HI; | 332 | "not.l %[sdab] \n" |
136 | DELAY; | 333 | |
137 | if ( SDA ) | 334 | "moveq.l #8,%%d1 \n" /* i = 8 */ |
138 | byte |= i; | 335 | "clr.l %[byte] \n" /* byte = 0 */ |
139 | SCL_LO; | 336 | |
140 | DELAY; | 337 | "2: \n" /* do */ |
141 | SDA_OUTPUT; | 338 | "not.l %[sclb] \n" /* SCL_HI_IN */ |
142 | } | 339 | "and.l %[sclb],(8,%[gpio]) \n" |
143 | 340 | "not.l %[sclb] \n" | |
144 | pcf50606_i2c_ack(ack); | 341 | "1: \n" |
342 | "move.l (%[gpio]),%%d0 \n" | ||
343 | "btst.l #12,%%d0 \n" | ||
344 | "beq.s 1b \n" | ||
345 | |||
346 | "move.l %[dly],%%d0 \n" /* DELAY */ | ||
347 | "1: \n" | ||
348 | "subq.l #1,%%d0 \n" | ||
349 | "bhi.s 1b \n" | ||
350 | |||
351 | "lsl.l #1,%[byte] \n" /* byte <<= 1 */ | ||
352 | "move.l (%[gpi1]),%%d0 \n" /* if (SDA) */ | ||
353 | "btst.l #13,%%d0 \n" | ||
354 | "beq.s 1f \n" | ||
355 | "addq.l #1,%[byte] \n" /* byte++ */ | ||
356 | "1: \n" | ||
357 | |||
358 | "or.l %[sclb],(8,%[gpio]) \n" /* SCL_LO_OUT */ | ||
359 | |||
360 | "move.l %[dly],%%d0 \n" /* DELAY */ | ||
361 | "1: \n" | ||
362 | "subq.l #1,%%d0 \n" | ||
363 | "bhi.s 1b \n" | ||
364 | |||
365 | "subq.l #1,%%d1 \n" /* i-- */ | ||
366 | "bne.s 2b \n" /* while (i != 0) */ | ||
367 | : /* outputs */ | ||
368 | [byte]"=&d"(byte) | ||
369 | : /* inputs */ | ||
370 | [gpio]"a"(&GPIO_READ), | ||
371 | [sclb]"d"(0x00001000), | ||
372 | [gpi1]"a"(&GPIO1_READ), | ||
373 | [sdab]"d"(0x00002000), | ||
374 | [dly] "d"(i2c_delay) | ||
375 | : /* clobbers */ | ||
376 | "d0", "d1" | ||
377 | ); | ||
378 | #else | ||
379 | int i; | ||
380 | |||
381 | /* clock in each bit, MSB first */ | ||
382 | SDA_HI_IN; | ||
383 | for ( i=0x80; i; i>>=1 ) | ||
384 | { | ||
385 | SCL_HI_IN; | ||
386 | DELAY; | ||
387 | if ( SDA ) | ||
388 | byte |= i; | ||
389 | SCL_LO_OUT; | ||
390 | DELAY; | ||
391 | } | ||
392 | #endif | ||
393 | |||
394 | pcf50606_i2c_ack(ack); | ||
145 | 395 | ||
146 | return byte; | 396 | return byte; |
147 | } | 397 | } |
148 | 398 | ||
149 | int pcf50606_i2c_write(int address, const unsigned char* buf, int count) | 399 | int pcf50606_i2c_write(int address, const unsigned char* buf, int count) |
@@ -270,12 +520,12 @@ static void set_voltages(void) | |||
270 | void pcf50606_init(void) | 520 | void pcf50606_init(void) |
271 | { | 521 | { |
272 | /* Bit banged I2C */ | 522 | /* Bit banged I2C */ |
273 | or_l(0x00002000, &GPIO1_OUT); | ||
274 | or_l(0x00001000, &GPIO_OUT); | ||
275 | or_l(0x00002000, &GPIO1_ENABLE); | ||
276 | or_l(0x00001000, &GPIO_ENABLE); | ||
277 | or_l(0x00002000, &GPIO1_FUNCTION); | 523 | or_l(0x00002000, &GPIO1_FUNCTION); |
278 | or_l(0x00001000, &GPIO_FUNCTION); | 524 | or_l(0x00001000, &GPIO_FUNCTION); |
525 | and_l(~0x00002000, &GPIO1_OUT); | ||
526 | and_l(~0x00001000, &GPIO_OUT); | ||
527 | and_l(~0x00002000, &GPIO1_ENABLE); | ||
528 | and_l(~0x00001000, &GPIO_ENABLE); | ||
279 | 529 | ||
280 | set_voltages(); | 530 | set_voltages(); |
281 | 531 | ||