diff options
author | Rafaël Carré <rafael.carre@gmail.com> | 2010-06-01 10:16:10 +0000 |
---|---|---|
committer | Rafaël Carré <rafael.carre@gmail.com> | 2010-06-01 10:16:10 +0000 |
commit | df34a4767f9cb1478eb5e231484bba9124422c38 (patch) | |
tree | f6b8b7a2c66c63a846ee83e40187b8a8a124edd0 /firmware/target | |
parent | dc32a5b14ccad55ce1f1848a16d5605b9019ae87 (diff) | |
download | rockbox-df34a4767f9cb1478eb5e231484bba9124422c38.tar.gz rockbox-df34a4767f9cb1478eb5e231484bba9124422c38.zip |
as3525 ascodec: make internal functions statics and remove some details for ascodec-target.h header
reorder static functions to avoid the need for early prototypes
panic if the INT_AUDIO callback could not read the 3 IRQ_ENRD registers
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26445 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/arm/as3525/ascodec-as3525.c | 229 | ||||
-rw-r--r-- | firmware/target/arm/as3525/ascodec-target.h | 48 |
2 files changed, 123 insertions, 154 deletions
diff --git a/firmware/target/arm/as3525/ascodec-as3525.c b/firmware/target/arm/as3525/ascodec-as3525.c index 708215deed..54a579ad0d 100644 --- a/firmware/target/arm/as3525/ascodec-as3525.c +++ b/firmware/target/arm/as3525/ascodec-as3525.c | |||
@@ -88,6 +88,31 @@ | |||
88 | #define IFDEBUG(x) | 88 | #define IFDEBUG(x) |
89 | #endif | 89 | #endif |
90 | 90 | ||
91 | #define ASCODEC_REQ_READ 0 | ||
92 | #define ASCODEC_REQ_WRITE 1 | ||
93 | |||
94 | /* | ||
95 | * How many bytes we using in struct ascodec_request for the data buffer. | ||
96 | * 4 fits the alignment best right now. | ||
97 | * We don't actually use more than 3 at the moment (when reading interrupts) | ||
98 | * Upper limit would be 255 since DACNT is 8 bits! | ||
99 | */ | ||
100 | #define ASCODEC_REQ_MAXLEN 4 | ||
101 | |||
102 | typedef void (ascodec_cb_fn)(unsigned const char *data, unsigned cnt); | ||
103 | |||
104 | struct ascodec_request { | ||
105 | unsigned char type; | ||
106 | unsigned char index; | ||
107 | unsigned char status; | ||
108 | unsigned char cnt; | ||
109 | unsigned char data[ASCODEC_REQ_MAXLEN]; | ||
110 | struct wakeup wkup; | ||
111 | ascodec_cb_fn *callback; | ||
112 | struct ascodec_request *next; | ||
113 | }; | ||
114 | |||
115 | |||
91 | static struct mutex as_mtx; | 116 | static struct mutex as_mtx; |
92 | 117 | ||
93 | static int ascodec_enrd0_shadow = 0; | 118 | static int ascodec_enrd0_shadow = 0; |
@@ -110,18 +135,94 @@ static int int_rtc = 0; | |||
110 | static int int_adc = 0; | 135 | static int int_adc = 0; |
111 | #endif /* DEBUG */ | 136 | #endif /* DEBUG */ |
112 | 137 | ||
113 | static void ascodec_read_cb(unsigned const char *data, unsigned int len); | 138 | /* returns != 0 when busy */ |
139 | static inline int i2c_busy(void) | ||
140 | { | ||
141 | return (I2C2_SR & 1); | ||
142 | } | ||
143 | |||
144 | static void ascodec_finish_req(struct ascodec_request *req) | ||
145 | { | ||
146 | /* | ||
147 | * Wait if still busy, unfortunately this happens since | ||
148 | * the controller is running at a low divisor, so it's | ||
149 | * still busy when we serviced the interrupt. | ||
150 | * I tried upping the i2c speed to 4MHz which | ||
151 | * made the number of busywait cycles much smaller | ||
152 | * (none for reads and only a few for writes), | ||
153 | * but who knows if it's reliable at that frequency. ;) | ||
154 | * For one thing, 8MHz doesn't work, so 4MHz is likely | ||
155 | * borderline. | ||
156 | * In general writes need much more wait cycles than reads | ||
157 | * for some reason, possibly because we read the data register | ||
158 | * for reads, which will likely block the processor while | ||
159 | * the i2c controller responds to the register read. | ||
160 | */ | ||
161 | while (i2c_busy()); | ||
162 | |||
163 | /* disable clock */ | ||
164 | CGU_PERI &= ~CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE; | ||
114 | 165 | ||
115 | static void ascodec_start_req(struct ascodec_request *req); | 166 | req->status = 1; |
116 | static int ascodec_continue_req(struct ascodec_request *req, int irq_status); | ||
117 | static void ascodec_finish_req(struct ascodec_request *req); | ||
118 | 167 | ||
119 | void INT_AUDIO(void) | 168 | if (req->callback) { |
169 | req->callback(req->data, req_data_ptr - req->data); | ||
170 | } | ||
171 | wakeup_signal(&req->wkup); | ||
172 | |||
173 | req_head = req->next; | ||
174 | req->next = NULL; | ||
175 | if (req_head == NULL) | ||
176 | req_tail = NULL; | ||
177 | |||
178 | } | ||
179 | |||
180 | static int ascodec_continue_req(struct ascodec_request *req, int irq_status) | ||
120 | { | 181 | { |
121 | VIC_INT_EN_CLEAR = INTERRUPT_AUDIO; | 182 | if ((irq_status & (I2C2_IRQ_RXOVER|I2C2_IRQ_ACKTIMEO)) > 0) { |
122 | IFDEBUG(int_audio_ctr++); | 183 | /* some error occured, restart the request */ |
184 | return REQ_RETRY; | ||
185 | } | ||
186 | if (req->type == ASCODEC_REQ_READ && | ||
187 | (irq_status & I2C2_IRQ_RXFULL) > 0) { | ||
188 | *(req_data_ptr++) = I2C2_DATA; | ||
189 | } else { | ||
190 | if (req->cnt > 1 && | ||
191 | (irq_status & I2C2_IRQ_TXEMPTY) > 0) { | ||
192 | I2C2_DATA = *(req_data_ptr++); | ||
193 | } | ||
194 | } | ||
123 | 195 | ||
124 | ascodec_async_read(AS3514_IRQ_ENRD0, 3, &as_audio_req, ascodec_read_cb); | 196 | req->index++; |
197 | if (--req->cnt > 0) | ||
198 | return REQ_UNFINISHED; | ||
199 | |||
200 | return REQ_FINISHED; | ||
201 | } | ||
202 | |||
203 | static void ascodec_start_req(struct ascodec_request *req) | ||
204 | { | ||
205 | int unmask = 0; | ||
206 | |||
207 | /* enable clock */ | ||
208 | CGU_PERI |= CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE; | ||
209 | |||
210 | /* start transfer */ | ||
211 | I2C2_SADDR = req->index; | ||
212 | if (req->type == ASCODEC_REQ_READ) { | ||
213 | req_data_ptr = req->data; | ||
214 | /* start transfer */ | ||
215 | I2C2_CNTRL = I2C2_CNTRL_DEFAULT | I2C2_CNTRL_READ; | ||
216 | unmask = I2C2_IRQ_RXFULL|I2C2_IRQ_RXOVER; | ||
217 | } else { | ||
218 | req_data_ptr = &req->data[1]; | ||
219 | I2C2_CNTRL = I2C2_CNTRL_DEFAULT | I2C2_CNTRL_WRITE; | ||
220 | I2C2_DATA = req->data[0]; | ||
221 | unmask = I2C2_IRQ_TXEMPTY|I2C2_IRQ_ACKTIMEO; | ||
222 | } | ||
223 | |||
224 | I2C2_DACNT = req->cnt; | ||
225 | I2C2_IMR |= unmask; /* enable interrupts */ | ||
125 | } | 226 | } |
126 | 227 | ||
127 | void INT_I2C_AUDIO(void) | 228 | void INT_I2C_AUDIO(void) |
@@ -207,13 +308,7 @@ void ascodec_init(void) | |||
207 | #endif | 308 | #endif |
208 | } | 309 | } |
209 | 310 | ||
210 | /* returns != 0 when busy */ | 311 | static void ascodec_req_init(struct ascodec_request *req, int type, |
211 | static int i2c_busy(void) | ||
212 | { | ||
213 | return (I2C2_SR & 1); | ||
214 | } | ||
215 | |||
216 | void ascodec_req_init(struct ascodec_request *req, int type, | ||
217 | unsigned int index, unsigned int cnt) | 312 | unsigned int index, unsigned int cnt) |
218 | { | 313 | { |
219 | wakeup_init(&req->wkup); | 314 | wakeup_init(&req->wkup); |
@@ -224,7 +319,7 @@ void ascodec_req_init(struct ascodec_request *req, int type, | |||
224 | req->cnt = cnt; | 319 | req->cnt = cnt; |
225 | } | 320 | } |
226 | 321 | ||
227 | void ascodec_submit(struct ascodec_request *req) | 322 | static void ascodec_submit(struct ascodec_request *req) |
228 | { | 323 | { |
229 | int oldlevel = disable_irq_save(); | 324 | int oldlevel = disable_irq_save(); |
230 | 325 | ||
@@ -241,90 +336,6 @@ void ascodec_submit(struct ascodec_request *req) | |||
241 | restore_irq(oldlevel); | 336 | restore_irq(oldlevel); |
242 | } | 337 | } |
243 | 338 | ||
244 | static void ascodec_start_req(struct ascodec_request *req) | ||
245 | { | ||
246 | int unmask = 0; | ||
247 | |||
248 | /* enable clock */ | ||
249 | CGU_PERI |= CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE; | ||
250 | |||
251 | /* start transfer */ | ||
252 | I2C2_SADDR = req->index; | ||
253 | if (req->type == ASCODEC_REQ_READ) { | ||
254 | req_data_ptr = req->data; | ||
255 | /* start transfer */ | ||
256 | I2C2_CNTRL = I2C2_CNTRL_DEFAULT | I2C2_CNTRL_READ; | ||
257 | unmask = I2C2_IRQ_RXFULL|I2C2_IRQ_RXOVER; | ||
258 | } else { | ||
259 | req_data_ptr = &req->data[1]; | ||
260 | I2C2_CNTRL = I2C2_CNTRL_DEFAULT | I2C2_CNTRL_WRITE; | ||
261 | I2C2_DATA = req->data[0]; | ||
262 | unmask = I2C2_IRQ_TXEMPTY|I2C2_IRQ_ACKTIMEO; | ||
263 | } | ||
264 | |||
265 | I2C2_DACNT = req->cnt; | ||
266 | I2C2_IMR |= unmask; /* enable interrupts */ | ||
267 | } | ||
268 | |||
269 | static int ascodec_continue_req(struct ascodec_request *req, int irq_status) | ||
270 | { | ||
271 | if ((irq_status & (I2C2_IRQ_RXOVER|I2C2_IRQ_ACKTIMEO)) > 0) { | ||
272 | /* some error occured, restart the request */ | ||
273 | return REQ_RETRY; | ||
274 | } | ||
275 | if (req->type == ASCODEC_REQ_READ && | ||
276 | (irq_status & I2C2_IRQ_RXFULL) > 0) { | ||
277 | *(req_data_ptr++) = I2C2_DATA; | ||
278 | } else { | ||
279 | if (req->cnt > 1 && | ||
280 | (irq_status & I2C2_IRQ_TXEMPTY) > 0) { | ||
281 | I2C2_DATA = *(req_data_ptr++); | ||
282 | } | ||
283 | } | ||
284 | |||
285 | req->index++; | ||
286 | if (--req->cnt > 0) | ||
287 | return REQ_UNFINISHED; | ||
288 | |||
289 | return REQ_FINISHED; | ||
290 | } | ||
291 | |||
292 | static void ascodec_finish_req(struct ascodec_request *req) | ||
293 | { | ||
294 | /* | ||
295 | * Wait if still busy, unfortunately this happens since | ||
296 | * the controller is running at a low divisor, so it's | ||
297 | * still busy when we serviced the interrupt. | ||
298 | * I tried upping the i2c speed to 4MHz which | ||
299 | * made the number of busywait cycles much smaller | ||
300 | * (none for reads and only a few for writes), | ||
301 | * but who knows if it's reliable at that frequency. ;) | ||
302 | * For one thing, 8MHz doesn't work, so 4MHz is likely | ||
303 | * borderline. | ||
304 | * In general writes need much more wait cycles than reads | ||
305 | * for some reason, possibly because we read the data register | ||
306 | * for reads, which will likely block the processor while | ||
307 | * the i2c controller responds to the register read. | ||
308 | */ | ||
309 | while (i2c_busy()); | ||
310 | |||
311 | /* disable clock */ | ||
312 | CGU_PERI &= ~CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE; | ||
313 | |||
314 | req->status = 1; | ||
315 | |||
316 | if (req->callback) { | ||
317 | req->callback(req->data, req_data_ptr - req->data); | ||
318 | } | ||
319 | wakeup_signal(&req->wkup); | ||
320 | |||
321 | req_head = req->next; | ||
322 | req->next = NULL; | ||
323 | if (req_head == NULL) | ||
324 | req_tail = NULL; | ||
325 | |||
326 | } | ||
327 | |||
328 | static int irq_disabled(void) | 339 | static int irq_disabled(void) |
329 | { | 340 | { |
330 | unsigned long cpsr; | 341 | unsigned long cpsr; |
@@ -350,9 +361,8 @@ static void ascodec_wait(struct ascodec_request *req) | |||
350 | * The request struct passed in must be allocated statically. | 361 | * The request struct passed in must be allocated statically. |
351 | * If you call ascodec_async_write from different places, each | 362 | * If you call ascodec_async_write from different places, each |
352 | * call needs it's own request struct. | 363 | * call needs it's own request struct. |
353 | * This comment is duplicated in .c and .h for your convenience. | ||
354 | */ | 364 | */ |
355 | void ascodec_async_write(unsigned int index, unsigned int value, | 365 | static void ascodec_async_write(unsigned int index, unsigned int value, |
356 | struct ascodec_request *req) | 366 | struct ascodec_request *req) |
357 | { | 367 | { |
358 | if (index == AS3514_CVDD_DCDC3) /* prevent setting of the LREG_CP_not bit */ | 368 | if (index == AS3514_CVDD_DCDC3) /* prevent setting of the LREG_CP_not bit */ |
@@ -380,9 +390,8 @@ int ascodec_write(unsigned int index, unsigned int value) | |||
380 | * call needs it's own request struct. | 390 | * call needs it's own request struct. |
381 | * If len is bigger than ASCODEC_REQ_MAXLEN it will be | 391 | * If len is bigger than ASCODEC_REQ_MAXLEN it will be |
382 | * set to ASCODEC_REQ_MAXLEN. | 392 | * set to ASCODEC_REQ_MAXLEN. |
383 | * This comment is duplicated in .c and .h for your convenience. | ||
384 | */ | 393 | */ |
385 | void ascodec_async_read(unsigned int index, unsigned int len, | 394 | static void ascodec_async_read(unsigned int index, unsigned int len, |
386 | struct ascodec_request *req, ascodec_cb_fn *cb) | 395 | struct ascodec_request *req, ascodec_cb_fn *cb) |
387 | { | 396 | { |
388 | if (len > ASCODEC_REQ_MAXLEN) | 397 | if (len > ASCODEC_REQ_MAXLEN) |
@@ -433,8 +442,8 @@ int ascodec_readbytes(unsigned int index, unsigned int len, unsigned char *data) | |||
433 | 442 | ||
434 | static void ascodec_read_cb(unsigned const char *data, unsigned int len) | 443 | static void ascodec_read_cb(unsigned const char *data, unsigned int len) |
435 | { | 444 | { |
436 | if (len != 3) /* some error happened? */ | 445 | if (UNLIKELY(len != 3)) /* some error happened? */ |
437 | return; | 446 | panicf("INT_AUDIO callback got %d regs", len); |
438 | 447 | ||
439 | if (data[0] & CHG_ENDOFCH) { /* chg finished */ | 448 | if (data[0] & CHG_ENDOFCH) { /* chg finished */ |
440 | ascodec_enrd0_shadow |= CHG_ENDOFCH; | 449 | ascodec_enrd0_shadow |= CHG_ENDOFCH; |
@@ -472,6 +481,14 @@ static void ascodec_read_cb(unsigned const char *data, unsigned int len) | |||
472 | VIC_INT_ENABLE = INTERRUPT_AUDIO; | 481 | VIC_INT_ENABLE = INTERRUPT_AUDIO; |
473 | } | 482 | } |
474 | 483 | ||
484 | void INT_AUDIO(void) | ||
485 | { | ||
486 | VIC_INT_EN_CLEAR = INTERRUPT_AUDIO; | ||
487 | IFDEBUG(int_audio_ctr++); | ||
488 | |||
489 | ascodec_async_read(AS3514_IRQ_ENRD0, 3, &as_audio_req, ascodec_read_cb); | ||
490 | } | ||
491 | |||
475 | void ascodec_wait_adc_finished(void) | 492 | void ascodec_wait_adc_finished(void) |
476 | { | 493 | { |
477 | wakeup_wait(&adc_wkup, TIMEOUT_BLOCK); | 494 | wakeup_wait(&adc_wkup, TIMEOUT_BLOCK); |
diff --git a/firmware/target/arm/as3525/ascodec-target.h b/firmware/target/arm/as3525/ascodec-target.h index a92fea9f61..7c47bd7e9c 100644 --- a/firmware/target/arm/as3525/ascodec-target.h +++ b/firmware/target/arm/as3525/ascodec-target.h | |||
@@ -46,30 +46,6 @@ | |||
46 | #define CVDD_1_10 2 | 46 | #define CVDD_1_10 2 |
47 | #define CVDD_1_05 3 | 47 | #define CVDD_1_05 3 |
48 | 48 | ||
49 | #define ASCODEC_REQ_READ 0 | ||
50 | #define ASCODEC_REQ_WRITE 1 | ||
51 | |||
52 | /* | ||
53 | * How many bytes we using in struct ascodec_request for the data buffer. | ||
54 | * 4 fits the alignment best right now. | ||
55 | * We don't actually use more than 3 at the moment (when reading interrupts) | ||
56 | * Upper limit would be 255 since DACNT is 8 bits! | ||
57 | */ | ||
58 | #define ASCODEC_REQ_MAXLEN 4 | ||
59 | |||
60 | typedef void (ascodec_cb_fn)(unsigned const char *data, unsigned cnt); | ||
61 | |||
62 | struct ascodec_request { | ||
63 | unsigned char type; | ||
64 | unsigned char index; | ||
65 | unsigned char status; | ||
66 | unsigned char cnt; | ||
67 | unsigned char data[ASCODEC_REQ_MAXLEN]; | ||
68 | struct wakeup wkup; | ||
69 | ascodec_cb_fn *callback; | ||
70 | struct ascodec_request *next; | ||
71 | }; | ||
72 | |||
73 | void ascodec_init(void) INIT_ATTR; | 49 | void ascodec_init(void) INIT_ATTR; |
74 | 50 | ||
75 | int ascodec_write(unsigned int index, unsigned int value); | 51 | int ascodec_write(unsigned int index, unsigned int value); |
@@ -78,30 +54,6 @@ int ascodec_read(unsigned int index); | |||
78 | 54 | ||
79 | int ascodec_readbytes(unsigned int index, unsigned int len, unsigned char *data); | 55 | int ascodec_readbytes(unsigned int index, unsigned int len, unsigned char *data); |
80 | 56 | ||
81 | /* | ||
82 | * The request struct passed in must be allocated statically. | ||
83 | * If you call ascodec_async_write from different places, each | ||
84 | * call needs it's own request struct. | ||
85 | * This comment is duplicated in .c and .h for your convenience. | ||
86 | */ | ||
87 | void ascodec_async_write(unsigned index, unsigned int value, struct ascodec_request *req); | ||
88 | |||
89 | /* | ||
90 | * The request struct passed in must be allocated statically. | ||
91 | * If you call ascodec_async_read from different places, each | ||
92 | * call needs it's own request struct. | ||
93 | * If len is bigger than ASCODEC_REQ_MAXLEN it will be | ||
94 | * set to ASCODEC_REQ_MAXLEN. | ||
95 | * This comment is duplicated in .c and .h for your convenience. | ||
96 | */ | ||
97 | void ascodec_async_read(unsigned index, unsigned int len, | ||
98 | struct ascodec_request *req, ascodec_cb_fn *cb); | ||
99 | |||
100 | void ascodec_req_init(struct ascodec_request *req, int type, | ||
101 | unsigned int index, unsigned int cnt); | ||
102 | |||
103 | void ascodec_submit(struct ascodec_request *req); | ||
104 | |||
105 | void ascodec_lock(void); | 57 | void ascodec_lock(void); |
106 | 58 | ||
107 | void ascodec_unlock(void); | 59 | void ascodec_unlock(void); |