diff options
author | Jens Arnold <amiconn@rockbox.org> | 2007-10-15 16:45:46 +0000 |
---|---|---|
committer | Jens Arnold <amiconn@rockbox.org> | 2007-10-15 16:45:46 +0000 |
commit | 3a5509a8d7829d731dd2c20a44588b8c15b2a540 (patch) | |
tree | 20e6f9e4d78019d5d73c52836d6fd1503f69f3b4 | |
parent | 52040a05a24bef3889ef01729280416923663697 (diff) | |
download | rockbox-3a5509a8d7829d731dd2c20a44588b8c15b2a540.tar.gz rockbox-3a5509a8d7829d731dd2c20a44588b8c15b2a540.zip |
Fix coldfire PCF50606 I2C driver, and iriver FM radio I2C driver. Both drivers had wrong timing, discovered while experimenting with buffered writes.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15122 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | firmware/drivers/fmradio_i2c.c | 83 | ||||
-rw-r--r-- | firmware/target/coldfire/pcf50606-coldfire.c | 40 |
2 files changed, 60 insertions, 63 deletions
diff --git a/firmware/drivers/fmradio_i2c.c b/firmware/drivers/fmradio_i2c.c index 0a1d0c1fd7..9f890ca34a 100644 --- a/firmware/drivers/fmradio_i2c.c +++ b/firmware/drivers/fmradio_i2c.c | |||
@@ -49,11 +49,10 @@ int fmradio_i2c_read(unsigned char address, unsigned char* buf, int count) | |||
49 | #ifdef IRIVER_H300_SERIES | 49 | #ifdef IRIVER_H300_SERIES |
50 | 50 | ||
51 | /* SDA is GPIO57 */ | 51 | /* SDA is GPIO57 */ |
52 | #define SDA_LO and_l(~0x02000000, &GPIO1_OUT) | 52 | #define SDA_OUTINIT and_l(~0x02000000, &GPIO1_OUT) |
53 | #define SDA_HI or_l( 0x02000000, &GPIO1_OUT) | 53 | #define SDA_HI_IN and_l(~0x02000000, &GPIO1_ENABLE) |
54 | #define SDA_INPUT and_l(~0x02000000, &GPIO1_ENABLE) | 54 | #define SDA_LO_OUT or_l( 0x02000000, &GPIO1_ENABLE) |
55 | #define SDA_OUTPUT or_l( 0x02000000, &GPIO1_ENABLE) | 55 | #define SDA ( 0x02000000 & GPIO1_READ) |
56 | #define SDA ( 0x02000000 & GPIO1_READ) | ||
57 | 56 | ||
58 | /* SCL is GPIO56 */ | 57 | /* SCL is GPIO56 */ |
59 | #define SCL_INPUT and_l(~0x01000000, &GPIO1_ENABLE) | 58 | #define SCL_INPUT and_l(~0x01000000, &GPIO1_ENABLE) |
@@ -65,11 +64,10 @@ int fmradio_i2c_read(unsigned char address, unsigned char* buf, int count) | |||
65 | #else | 64 | #else |
66 | 65 | ||
67 | /* SDA is GPIO55 */ | 66 | /* SDA is GPIO55 */ |
68 | #define SDA_LO and_l(~0x00800000, &GPIO1_OUT) | 67 | #define SDA_OUTINIT and_l(~0x00800000, &GPIO1_OUT) |
69 | #define SDA_HI or_l( 0x00800000, &GPIO1_OUT) | 68 | #define SDA_HI_IN and_l(~0x00800000, &GPIO1_ENABLE) |
70 | #define SDA_INPUT and_l(~0x00800000, &GPIO1_ENABLE) | 69 | #define SDA_LO_OUT or_l( 0x00800000, &GPIO1_ENABLE) |
71 | #define SDA_OUTPUT or_l( 0x00800000, &GPIO1_ENABLE) | 70 | #define SDA ( 0x00800000 & GPIO1_READ) |
72 | #define SDA ( 0x00800000 & GPIO1_READ) | ||
73 | 71 | ||
74 | /* SCL is GPIO3 */ | 72 | /* SCL is GPIO3 */ |
75 | #define SCL_INPUT and_l(~0x00000008, &GPIO_ENABLE) | 73 | #define SCL_INPUT and_l(~0x00000008, &GPIO_ENABLE) |
@@ -94,22 +92,23 @@ int fmradio_i2c_read(unsigned char address, unsigned char* buf, int count) | |||
94 | 92 | ||
95 | static void fmradio_i2c_start(void) | 93 | static void fmradio_i2c_start(void) |
96 | { | 94 | { |
97 | SDA_OUTPUT; | ||
98 | SCL_OUTPUT; | ||
99 | SDA_HI; | ||
100 | SCL_HI; | 95 | SCL_HI; |
96 | SCL_OUTPUT; | ||
97 | SDA_HI_IN; | ||
98 | SDA_OUTINIT; | ||
101 | DELAY; | 99 | DELAY; |
102 | SDA_LO; | 100 | SDA_LO_OUT; |
103 | DELAY; | 101 | DELAY; |
104 | SCL_LO; | 102 | SCL_LO; |
105 | } | 103 | } |
106 | 104 | ||
107 | static void fmradio_i2c_stop(void) | 105 | static void fmradio_i2c_stop(void) |
108 | { | 106 | { |
109 | SDA_LO; | 107 | SDA_LO_OUT; |
108 | DELAY; | ||
110 | SCL_HI; | 109 | SCL_HI; |
111 | DELAY; | 110 | DELAY; |
112 | SDA_HI; | 111 | SDA_HI_IN; |
113 | } | 112 | } |
114 | 113 | ||
115 | /* Generate ACK or NACK */ | 114 | /* Generate ACK or NACK */ |
@@ -123,23 +122,21 @@ static void fmradio_i2c_ack(bool nack) | |||
123 | In their infinite wisdom, iriver didn't pull up the SCL line, so | 122 | In their infinite wisdom, iriver didn't pull up the SCL line, so |
124 | we have to drive the SCL high repeatedly to simulate a pullup. */ | 123 | we have to drive the SCL high repeatedly to simulate a pullup. */ |
125 | 124 | ||
126 | SCL_LO; /* Set the clock low */ | ||
127 | |||
128 | if (nack) | 125 | if (nack) |
129 | SDA_HI; | 126 | SDA_HI_IN; |
130 | else | 127 | else |
131 | SDA_LO; | 128 | SDA_LO_OUT; |
132 | 129 | DELAY; | |
133 | SCL_INPUT; /* Set the clock to input */ | 130 | |
134 | while(!SCL) /* and wait for the slave to release it */ | 131 | SCL_HI; |
132 | do | ||
135 | { | 133 | { |
136 | SCL_HI; | ||
137 | SCL_OUTPUT; /* Set the clock to output */ | 134 | SCL_OUTPUT; /* Set the clock to output */ |
138 | SCL_INPUT; /* Set the clock to input */ | 135 | SCL_INPUT; /* Set the clock to input */ |
139 | DELAY; | 136 | DELAY; |
140 | } | 137 | } |
138 | while(!SCL); /* and wait for the slave to release it */ | ||
141 | 139 | ||
142 | DELAY; | ||
143 | SCL_OUTPUT; | 140 | SCL_OUTPUT; |
144 | SCL_LO; | 141 | SCL_LO; |
145 | } | 142 | } |
@@ -156,24 +153,23 @@ static int fmradio_i2c_getack(void) | |||
156 | In their infinite wisdom, iriver didn't pull up the SCL line, so | 153 | In their infinite wisdom, iriver didn't pull up the SCL line, so |
157 | we have to drive the SCL high repeatedly to simulate a pullup. */ | 154 | we have to drive the SCL high repeatedly to simulate a pullup. */ |
158 | 155 | ||
159 | SDA_INPUT; /* And set to input */ | 156 | SDA_HI_IN; |
160 | SCL_INPUT; /* Set the clock to input */ | 157 | DELAY; |
161 | while(!SCL) /* and wait for the slave to release it */ | 158 | |
159 | SCL_HI; /* set clock to high */ | ||
160 | do | ||
162 | { | 161 | { |
163 | SCL_HI; | ||
164 | SCL_OUTPUT; /* Set the clock to output */ | 162 | SCL_OUTPUT; /* Set the clock to output */ |
165 | SCL_INPUT; /* Set the clock to input */ | 163 | SCL_INPUT; /* Set the clock to input */ |
166 | DELAY; | 164 | DELAY; |
167 | } | 165 | } |
166 | while(!SCL); /* and wait for the slave to release it */ | ||
168 | 167 | ||
169 | if (SDA) | 168 | if (SDA) |
170 | /* ack failed */ | 169 | ret = 0; /* ack failed */ |
171 | ret = 0; | ||
172 | 170 | ||
173 | SCL_OUTPUT; | 171 | SCL_OUTPUT; |
174 | SCL_LO; | 172 | SCL_LO; |
175 | SDA_HI; | ||
176 | SDA_OUTPUT; | ||
177 | 173 | ||
178 | return ret; | 174 | return ret; |
179 | } | 175 | } |
@@ -185,20 +181,14 @@ static void fmradio_i2c_outb(unsigned char byte) | |||
185 | /* clock out each bit, MSB first */ | 181 | /* clock out each bit, MSB first */ |
186 | for ( i=0x80; i; i>>=1 ) { | 182 | for ( i=0x80; i; i>>=1 ) { |
187 | if ( i & byte ) | 183 | if ( i & byte ) |
188 | { | 184 | SDA_HI_IN; |
189 | SDA_HI; | ||
190 | } | ||
191 | else | 185 | else |
192 | { | 186 | SDA_LO_OUT; |
193 | SDA_LO; | ||
194 | } | ||
195 | DELAY; | 187 | DELAY; |
196 | SCL_HI; | 188 | SCL_HI; |
197 | DELAY; | 189 | DELAY; |
198 | SCL_LO; | 190 | SCL_LO; |
199 | } | 191 | } |
200 | |||
201 | SDA_HI; | ||
202 | } | 192 | } |
203 | 193 | ||
204 | static unsigned char fmradio_i2c_inb(void) | 194 | static unsigned char fmradio_i2c_inb(void) |
@@ -206,18 +196,15 @@ static unsigned char fmradio_i2c_inb(void) | |||
206 | int i; | 196 | int i; |
207 | unsigned char byte = 0; | 197 | unsigned char byte = 0; |
208 | 198 | ||
199 | SDA_HI_IN; | ||
209 | /* clock in each bit, MSB first */ | 200 | /* clock in each bit, MSB first */ |
210 | for ( i=0x80; i; i>>=1 ) { | 201 | for ( i=0x80; i; i>>=1 ) { |
211 | SDA_INPUT; /* And set to input */ | ||
212 | DELAY; | 202 | DELAY; |
203 | SCL_HI; | ||
213 | DELAY; | 204 | DELAY; |
214 | if ( SDA ) | 205 | if ( SDA ) |
215 | byte |= i; | 206 | byte |= i; |
216 | SCL_HI; | ||
217 | DELAY; | ||
218 | SCL_LO; | 207 | SCL_LO; |
219 | DELAY; | ||
220 | SDA_OUTPUT; | ||
221 | } | 208 | } |
222 | 209 | ||
223 | return byte; | 210 | return byte; |
@@ -278,14 +265,14 @@ int fmradio_i2c_read(int address, unsigned char* buf, int count) | |||
278 | #define SDA_HI or_b(0x10, &PBDRL) | 265 | #define SDA_HI or_b(0x10, &PBDRL) |
279 | #define SDA_INPUT and_b(~0x10, &PBIORL) | 266 | #define SDA_INPUT and_b(~0x10, &PBIORL) |
280 | #define SDA_OUTPUT or_b(0x10, &PBIORL) | 267 | #define SDA_OUTPUT or_b(0x10, &PBIORL) |
281 | #define SDA (PBDR & 0x0010) | 268 | #define SDA (PBDR & 0x0010) |
282 | 269 | ||
283 | /* SCL is PB1 */ | 270 | /* SCL is PB1 */ |
284 | #define SCL_INPUT and_b(~0x02, &PBIORL) | 271 | #define SCL_INPUT and_b(~0x02, &PBIORL) |
285 | #define SCL_OUTPUT or_b(0x02, &PBIORL) | 272 | #define SCL_OUTPUT or_b(0x02, &PBIORL) |
286 | #define SCL_LO and_b(~0x02, &PBDRL) | 273 | #define SCL_LO and_b(~0x02, &PBDRL) |
287 | #define SCL_HI or_b(0x02, &PBDRL) | 274 | #define SCL_HI or_b(0x02, &PBDRL) |
288 | #define SCL (PBDR & 0x0002) | 275 | #define SCL (PBDR & 0x0002) |
289 | 276 | ||
290 | /* arbitrary delay loop */ | 277 | /* arbitrary delay loop */ |
291 | #define DELAY do { int _x; for(_x=0;_x<20;_x++);} while (0) | 278 | #define DELAY do { int _x; for(_x=0;_x<20;_x++);} while (0) |
diff --git a/firmware/target/coldfire/pcf50606-coldfire.c b/firmware/target/coldfire/pcf50606-coldfire.c index d777b41cb1..d57b249f0d 100644 --- a/firmware/target/coldfire/pcf50606-coldfire.c +++ b/firmware/target/coldfire/pcf50606-coldfire.c | |||
@@ -140,6 +140,11 @@ inline void pcf50606_i2c_stop(void) | |||
140 | asm ( | 140 | asm ( |
141 | "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */ | 141 | "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */ |
142 | 142 | ||
143 | "move.l %[dly],%%d0 \n" /* DELAY */ | ||
144 | "1: \n" | ||
145 | "subq.l #1,%%d0 \n" | ||
146 | "bhi.s 1b \n" | ||
147 | |||
143 | "not.l %[sclb] \n" /* SCL_HI_IN */ | 148 | "not.l %[sclb] \n" /* SCL_HI_IN */ |
144 | "and.l %[sclb],(8,%[sclrd]) \n" | 149 | "and.l %[sclb],(8,%[sclrd]) \n" |
145 | "not.l %[sclb] \n" | 150 | "not.l %[sclb] \n" |
@@ -169,6 +174,7 @@ inline void pcf50606_i2c_stop(void) | |||
169 | ); | 174 | ); |
170 | #else | 175 | #else |
171 | SDA_LO_OUT; | 176 | SDA_LO_OUT; |
177 | DELAY; | ||
172 | SCL_HI_IN; | 178 | SCL_HI_IN; |
173 | DELAY; | 179 | DELAY; |
174 | SDA_HI_IN; | 180 | SDA_HI_IN; |
@@ -189,6 +195,11 @@ inline void pcf50606_i2c_ack(bool ack) | |||
189 | "1: \n" | 195 | "1: \n" |
190 | "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */ | 196 | "or.l %[sdab],(8,%[sdard]) \n" /* SDA_LO_OUT */ |
191 | 197 | ||
198 | "move.l %[dly],%%d0 \n" /* DELAY */ | ||
199 | "1: \n" | ||
200 | "subq.l #1,%%d0 \n" | ||
201 | "bhi.s 1b \n" | ||
202 | |||
192 | "not.l %[sclb] \n" /* SCL_HI_IN */ | 203 | "not.l %[sclb] \n" /* SCL_HI_IN */ |
193 | "and.l %[sclb],(8,%[sclrd]) \n" | 204 | "and.l %[sclb],(8,%[sclrd]) \n" |
194 | "not.l %[sclb] \n" | 205 | "not.l %[sclb] \n" |
@@ -220,9 +231,8 @@ inline void pcf50606_i2c_ack(bool ack) | |||
220 | SDA_LO_OUT; | 231 | SDA_LO_OUT; |
221 | else | 232 | else |
222 | SDA_HI_IN; | 233 | SDA_HI_IN; |
223 | 234 | DELAY; | |
224 | SCL_HI_IN; | 235 | SCL_HI_IN; |
225 | |||
226 | DELAY; | 236 | DELAY; |
227 | SCL_LO_OUT; | 237 | SCL_LO_OUT; |
228 | #endif | 238 | #endif |
@@ -251,16 +261,16 @@ inline bool pcf50606_i2c_getack(void) | |||
251 | "btst.l %[sclbnum],%%d0 \n" | 261 | "btst.l %[sclbnum],%%d0 \n" |
252 | "beq.s 1b \n" | 262 | "beq.s 1b \n" |
253 | 263 | ||
264 | "move.l %[dly],%%d0 \n" /* DELAY */ | ||
265 | "1: \n" | ||
266 | "subq.l #1,%%d0 \n" | ||
267 | "bhi.s 1b \n" | ||
268 | |||
254 | "move.l (%[sdard]),%%d0 \n" /* ret = !SDA */ | 269 | "move.l (%[sdard]),%%d0 \n" /* ret = !SDA */ |
255 | "btst.l %[sdabnum],%%d0 \n" | 270 | "btst.l %[sdabnum],%%d0 \n" |
256 | "seq.b %[ret] \n" | 271 | "seq.b %[ret] \n" |
257 | 272 | ||
258 | "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ | 273 | "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ |
259 | |||
260 | "move.l %[dly],%%d0 \n" /* DELAY */ | ||
261 | "1: \n" | ||
262 | "subq.l #1,%%d0 \n" | ||
263 | "bhi.s 1b \n" | ||
264 | : /* outputs */ | 274 | : /* outputs */ |
265 | [ret] "=&d"(ret) | 275 | [ret] "=&d"(ret) |
266 | : /* inputs */ | 276 | : /* inputs */ |
@@ -278,11 +288,11 @@ inline bool pcf50606_i2c_getack(void) | |||
278 | SDA_HI_IN; | 288 | SDA_HI_IN; |
279 | DELAY; | 289 | DELAY; |
280 | SCL_HI_IN; | 290 | SCL_HI_IN; |
291 | DELAY; | ||
281 | 292 | ||
282 | ret = !SDA; | 293 | ret = !SDA; |
283 | 294 | ||
284 | SCL_LO_OUT; | 295 | SCL_LO_OUT; |
285 | DELAY; | ||
286 | #endif | 296 | #endif |
287 | return ret; | 297 | return ret; |
288 | } | 298 | } |
@@ -372,6 +382,11 @@ unsigned char pcf50606_i2c_inb(bool ack) | |||
372 | "clr.l %[byte] \n" /* byte = 0 */ | 382 | "clr.l %[byte] \n" /* byte = 0 */ |
373 | 383 | ||
374 | "2: \n" /* do */ | 384 | "2: \n" /* do */ |
385 | "move.l %[dly],%%d0 \n" /* DELAY */ | ||
386 | "1: \n" | ||
387 | "subq.l #1,%%d0 \n" | ||
388 | "bhi.s 1b \n" | ||
389 | |||
375 | "not.l %[sclb] \n" /* SCL_HI_IN */ | 390 | "not.l %[sclb] \n" /* SCL_HI_IN */ |
376 | "and.l %[sclb],(8,%[sclrd]) \n" | 391 | "and.l %[sclb],(8,%[sclrd]) \n" |
377 | "not.l %[sclb] \n" | 392 | "not.l %[sclb] \n" |
@@ -394,11 +409,6 @@ unsigned char pcf50606_i2c_inb(bool ack) | |||
394 | 409 | ||
395 | "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ | 410 | "or.l %[sclb],(8,%[sclrd]) \n" /* SCL_LO_OUT */ |
396 | 411 | ||
397 | "move.l %[dly],%%d0 \n" /* DELAY */ | ||
398 | "1: \n" | ||
399 | "subq.l #1,%%d0 \n" | ||
400 | "bhi.s 1b \n" | ||
401 | |||
402 | "subq.l #1,%%d1 \n" /* i-- */ | 412 | "subq.l #1,%%d1 \n" /* i-- */ |
403 | "bne.s 2b \n" /* while (i != 0) */ | 413 | "bne.s 2b \n" /* while (i != 0) */ |
404 | : /* outputs */ | 414 | : /* outputs */ |
@@ -421,12 +431,12 @@ unsigned char pcf50606_i2c_inb(bool ack) | |||
421 | SDA_HI_IN; | 431 | SDA_HI_IN; |
422 | for ( i=0x80; i; i>>=1 ) | 432 | for ( i=0x80; i; i>>=1 ) |
423 | { | 433 | { |
434 | DELAY; | ||
424 | SCL_HI_IN; | 435 | SCL_HI_IN; |
425 | DELAY; | 436 | DELAY; |
426 | if ( SDA ) | 437 | if ( SDA ) |
427 | byte |= i; | 438 | byte |= i; |
428 | SCL_LO_OUT; | 439 | SCL_LO_OUT; |
429 | DELAY; | ||
430 | } | 440 | } |
431 | #endif | 441 | #endif |
432 | 442 | ||