diff options
author | Linus Nielsen Feltzing <linus@haxx.se> | 2006-07-21 08:42:28 +0000 |
---|---|---|
committer | Linus Nielsen Feltzing <linus@haxx.se> | 2006-07-21 08:42:28 +0000 |
commit | ed4d7a33bdeba5ce11512ee617398a2840797203 (patch) | |
tree | 1027077148ace8e13c8fa49ae3794b2038a2d67a /firmware/drivers/i2c-coldfire.c | |
parent | e8818efbe9c814ad3b46ee0e5d0ae250b7c96cf4 (diff) | |
download | rockbox-ed4d7a33bdeba5ce11512ee617398a2840797203.tar.gz rockbox-ed4d7a33bdeba5ce11512ee617398a2840797203.zip |
Patch #5347 by Rani Hod - Adds FM radio and recording features to the iAudio X5.
Also includes a rewrite of the Coldfire I2C driver to include both read and write.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10272 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/drivers/i2c-coldfire.c')
-rw-r--r-- | firmware/drivers/i2c-coldfire.c | 229 |
1 files changed, 145 insertions, 84 deletions
diff --git a/firmware/drivers/i2c-coldfire.c b/firmware/drivers/i2c-coldfire.c index 47aeba757f..a628ce5f0e 100644 --- a/firmware/drivers/i2c-coldfire.c +++ b/firmware/drivers/i2c-coldfire.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * | ||
8 | * $Id$ | 9 | * $Id$ |
9 | * | 10 | * |
10 | * Copyright (C) 2005 by Andy Young | 11 | * Copyright (C) 2005 by Andy Young |
@@ -23,17 +24,16 @@ | |||
23 | #include "system.h" | 24 | #include "system.h" |
24 | #include "i2c-coldfire.h" | 25 | #include "i2c-coldfire.h" |
25 | 26 | ||
26 | #define I2C_DEVICE_1 ((volatile unsigned char *)&MADR) | ||
27 | #define I2C_DEVICE_2 ((volatile unsigned char *)&MADR2) | ||
28 | 27 | ||
29 | /* Local functions definitions */ | 28 | /* --- Local functions - declarations --- */ |
29 | |||
30 | static int i2c_start(volatile unsigned char *iface); | ||
31 | static int i2c_wait_for_slave(volatile unsigned char *iface); | ||
32 | static int i2c_outb(volatile unsigned char *iface, unsigned char byte); | ||
33 | inline void i2c_stop(volatile unsigned char *iface); | ||
30 | 34 | ||
31 | static int i2c_write_byte(int device, unsigned char data); | ||
32 | static int i2c_gen_start(int device); | ||
33 | static void i2c_gen_stop(int device); | ||
34 | static volatile unsigned char *i2c_get_addr(int device); | ||
35 | 35 | ||
36 | /* Public functions */ | 36 | /* --- Public functions - implementation --- */ |
37 | 37 | ||
38 | void i2c_init(void) | 38 | void i2c_init(void) |
39 | { | 39 | { |
@@ -55,14 +55,15 @@ void i2c_init(void) | |||
55 | #endif | 55 | #endif |
56 | 56 | ||
57 | /* I2C Clock divisor = 160 => 124.1556 MHz / 2 / 160 = 388.08 kHz */ | 57 | /* I2C Clock divisor = 160 => 124.1556 MHz / 2 / 160 = 388.08 kHz */ |
58 | MFDR = 0x0d; | 58 | MFDR = 0x0d; |
59 | MFDR2 = 0x0d; | 59 | MFDR2 = 0x0d; |
60 | 60 | ||
61 | #ifdef IAUDIO_X5 | 61 | #ifdef IAUDIO_X5 |
62 | MBCR = IEN; /* Enable interface */ | 62 | MBCR = IEN; /* Enable interface */ |
63 | MBCR2 = IEN; | ||
63 | #endif | 64 | #endif |
64 | 65 | ||
65 | #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) | 66 | #if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES) |
66 | /* Audio Codec */ | 67 | /* Audio Codec */ |
67 | MBDR = 0; /* iRiver firmware does this */ | 68 | MBDR = 0; /* iRiver firmware does this */ |
68 | MBCR = IEN; /* Enable interface */ | 69 | MBCR = IEN; /* Enable interface */ |
@@ -72,109 +73,169 @@ void i2c_init(void) | |||
72 | void i2c_close(void) | 73 | void i2c_close(void) |
73 | { | 74 | { |
74 | MBCR = 0; | 75 | MBCR = 0; |
76 | MBCR2 = 0; | ||
75 | } | 77 | } |
76 | 78 | ||
77 | /** | 79 | /* |
78 | * Writes bytes to the selected device. | 80 | * Writes bytes to a I2C device. |
79 | * | 81 | * |
80 | * Use device=1 for bus 1 at 0x40000280 | 82 | * Returns number of bytes successfully sent or a negative value on error. |
81 | * Use device=2 for bus 2 at 0x80000440 | ||
82 | * | ||
83 | * Returns number of bytes successfully send or -1 if START failed | ||
84 | */ | 83 | */ |
85 | int i2c_write(int device, unsigned char *buf, int count) | 84 | int i2c_write(volatile unsigned char *iface, unsigned char addr, |
85 | const unsigned char *buf, int count) | ||
86 | { | 86 | { |
87 | int i; | 87 | int i, rc; |
88 | int rc; | ||
89 | 88 | ||
90 | rc = i2c_gen_start(device); | 89 | if ( ! count) |
90 | return 0; | ||
91 | |||
92 | rc = i2c_start(iface); | ||
91 | if (rc < 0) | 93 | if (rc < 0) |
94 | return rc; | ||
95 | |||
96 | rc = i2c_outb(iface, addr & 0xfe); | ||
97 | if (rc < 0) | ||
98 | return rc; | ||
99 | |||
100 | for (i = 0; i < count; i++) | ||
92 | { | 101 | { |
93 | logf("i2c: gen_start failed (d=%d)", device); | 102 | rc = i2c_outb(iface, *buf++); |
94 | return rc*10 - 1; | ||
95 | } | ||
96 | |||
97 | for (i=0; i<count; i++) | ||
98 | { | ||
99 | rc = i2c_write_byte(device, buf[i]); | ||
100 | if (rc < 0) | 103 | if (rc < 0) |
101 | { | 104 | return rc; |
102 | logf("i2c: write failed at (d=%d,i=%d)", device, i); | ||
103 | return rc*10 - 2; | ||
104 | } | ||
105 | } | 105 | } |
106 | 106 | i2c_stop(iface); | |
107 | i2c_gen_stop(device); | 107 | |
108 | |||
109 | return count; | 108 | return count; |
110 | } | 109 | } |
111 | 110 | ||
112 | /* Write a byte to the interface, returns 0 on success, -1 otherwise. */ | 111 | /* |
113 | int i2c_write_byte(int device, unsigned char data) | 112 | * Reads bytes from a I2C device. |
113 | * | ||
114 | * Returns number of bytes successfully received or a negative value on error. | ||
115 | */ | ||
116 | int i2c_read(volatile unsigned char *iface, unsigned char addr, | ||
117 | unsigned char *buf, int count) | ||
114 | { | 118 | { |
115 | volatile unsigned char *regs = i2c_get_addr(device); | 119 | int i, rc; |
116 | 120 | ||
117 | long count = 0; | 121 | if ( ! count) |
122 | return 0; | ||
123 | |||
124 | rc = i2c_start(iface); | ||
125 | if (rc < 0) | ||
126 | return rc; | ||
118 | 127 | ||
119 | regs[O_MBDR] = data; /* Write data byte */ | 128 | rc = i2c_outb(iface, addr | 1); |
129 | if (rc < 0) | ||
130 | return rc; | ||
131 | |||
132 | /* Switch to Rx mode */ | ||
133 | iface[O_MBCR] &= ~MTX; | ||
134 | iface[O_MBCR] &= ~TXAK; | ||
135 | |||
136 | /* Dummy read */ | ||
137 | rc = (int) iface[O_MBDR]; | ||
138 | |||
139 | for (i = 0; i < count; i++) | ||
140 | { | ||
141 | rc = i2c_wait_for_slave(iface); | ||
142 | if (rc < 0) | ||
143 | return rc; | ||
120 | 144 | ||
121 | /* Wait for bus busy */ | 145 | if (i == count-2) |
122 | while (!(regs[O_MBSR] & IBB) && count < MAX_LOOP) | 146 | /* Don't ACK the next-to-last byte */ |
123 | count++; | 147 | iface[O_MBCR] |= TXAK; |
148 | |||
149 | if (i == count-1) | ||
150 | /* Generate STOP before reading last byte */ | ||
151 | i2c_stop(iface); | ||
124 | 152 | ||
125 | if (count >= MAX_LOOP) | 153 | *buf++ = iface[O_MBDR]; |
126 | return -1; | 154 | } |
155 | return count; | ||
156 | } | ||
127 | 157 | ||
128 | count = 0; | 158 | /* --- Local functions - implementation --- */ |
129 | 159 | ||
130 | /* Wait for interrupt flag */ | 160 | /* Begin I2C session on the given interface. |
131 | while (!(regs[O_MBSR] & IFF) && count < MAX_LOOP) | 161 | * |
132 | count++; | 162 | * Returns 0 on success, negative value on error. |
163 | */ | ||
164 | int i2c_start(volatile unsigned char *iface) | ||
165 | { | ||
166 | /* Wait for bus to become free */ | ||
167 | int j = MAX_LOOP; | ||
168 | while (--j && (iface[O_MBSR] & IBB)) | ||
169 | ; | ||
170 | if (!j) | ||
171 | { | ||
172 | logf("i2c: bus is busy (iface=%08x)", iface); | ||
173 | return -1; | ||
174 | } | ||
175 | |||
176 | /* Generate START and prepare for write */ | ||
177 | iface[O_MBCR] |= (MSTA | TXAK | MTX); | ||
178 | |||
179 | return 0; | ||
180 | } | ||
133 | 181 | ||
134 | if (count >= MAX_LOOP) | 182 | /* Wait for slave to act on given I2C interface. |
183 | * | ||
184 | * Returns 0 on success, negative value on error. | ||
185 | */ | ||
186 | int i2c_wait_for_slave(volatile unsigned char *iface) | ||
187 | { | ||
188 | int j = MAX_LOOP; | ||
189 | while (--j && ! (iface[O_MBSR] & IFF)) | ||
190 | ; | ||
191 | if (!j) | ||
192 | { | ||
193 | logf("i2c: IFF not set (iface=%08x)", iface); | ||
194 | i2c_stop(iface); | ||
135 | return -2; | 195 | return -2; |
136 | 196 | } | |
137 | regs[O_MBSR] &= ~IFF; /* Clear interrupt flag */ | 197 | |
138 | 198 | /* Clear interrupt flag */ | |
139 | if (!(regs[O_MBSR] & ICF)) /* Check that transfer is complete */ | 199 | iface[O_MBSR] &= ~IFF; |
140 | return -3; | 200 | |
141 | |||
142 | if (regs[O_MBSR] & RXAK) /* Check that the byte has been ACKed */ | ||
143 | return -4; | ||
144 | |||
145 | return 0; | 201 | return 0; |
146 | } | 202 | } |
147 | 203 | ||
148 | 204 | /* Write the given byte to the given I2C interface. | |
149 | /* Returns 0 on success, -1 on failure */ | 205 | * |
150 | int i2c_gen_start(int device) | 206 | * Returns 0 on success, negative value on error. |
207 | */ | ||
208 | int i2c_outb(volatile unsigned char *iface, unsigned char byte) | ||
151 | { | 209 | { |
152 | volatile unsigned char *regs = i2c_get_addr(device); | 210 | int rc; |
153 | long count = 0; | ||
154 | |||
155 | /* Wait for bus to become free */ | ||
156 | while ((regs[O_MBSR] & IBB) && (count < MAX_LOOP)) | ||
157 | count++; | ||
158 | |||
159 | if (count >= MAX_LOOP) | ||
160 | return -1; | ||
161 | 211 | ||
162 | regs[O_MBCR] |= MSTA | MTX; /* Generate START */ | 212 | iface[O_MBDR] = byte; |
163 | 213 | ||
214 | rc = i2c_wait_for_slave(iface); | ||
215 | if (rc < 0) | ||
216 | return rc; | ||
217 | |||
218 | /* Check that transfer is complete */ | ||
219 | if ( !(iface[O_MBSR] & ICF)) | ||
220 | { | ||
221 | logf("i2c: transfer error (iface=%08x)", iface); | ||
222 | i2c_stop(iface); | ||
223 | return -3; | ||
224 | } | ||
225 | |||
226 | /* Check that the byte has been ACKed */ | ||
227 | if (iface[O_MBSR] & RXAK) | ||
228 | { | ||
229 | logf("i2c: no ACK (iface=%08x)", iface); | ||
230 | i2c_stop(iface); | ||
231 | return -4; | ||
232 | } | ||
233 | |||
164 | return 0; | 234 | return 0; |
165 | } | ||
166 | |||
167 | void i2c_gen_stop(int device) | ||
168 | { | ||
169 | volatile unsigned char *regs = i2c_get_addr(device); | ||
170 | regs[O_MBCR] &= ~MSTA; /* Clear MSTA to generate STOP */ | ||
171 | } | 235 | } |
172 | 236 | ||
173 | 237 | /* End I2C session on the given interface. */ | |
174 | volatile unsigned char *i2c_get_addr(int device) | 238 | inline void i2c_stop(volatile unsigned char *iface) |
175 | { | 239 | { |
176 | if (device == 1) | 240 | iface[O_MBCR] &= ~MSTA; |
177 | return I2C_DEVICE_1; | ||
178 | |||
179 | return I2C_DEVICE_2; | ||
180 | } | 241 | } |