summaryrefslogtreecommitdiff
path: root/firmware/target/arm/as3525/ascodec-as3525.c
diff options
context:
space:
mode:
authorRafaël Carré <rafael.carre@gmail.com>2010-06-01 10:16:10 +0000
committerRafaël Carré <rafael.carre@gmail.com>2010-06-01 10:16:10 +0000
commitdf34a4767f9cb1478eb5e231484bba9124422c38 (patch)
treef6b8b7a2c66c63a846ee83e40187b8a8a124edd0 /firmware/target/arm/as3525/ascodec-as3525.c
parentdc32a5b14ccad55ce1f1848a16d5605b9019ae87 (diff)
downloadrockbox-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/arm/as3525/ascodec-as3525.c')
-rw-r--r--firmware/target/arm/as3525/ascodec-as3525.c229
1 files changed, 123 insertions, 106 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
102typedef void (ascodec_cb_fn)(unsigned const char *data, unsigned cnt);
103
104struct 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
91static struct mutex as_mtx; 116static struct mutex as_mtx;
92 117
93static int ascodec_enrd0_shadow = 0; 118static int ascodec_enrd0_shadow = 0;
@@ -110,18 +135,94 @@ static int int_rtc = 0;
110static int int_adc = 0; 135static int int_adc = 0;
111#endif /* DEBUG */ 136#endif /* DEBUG */
112 137
113static void ascodec_read_cb(unsigned const char *data, unsigned int len); 138/* returns != 0 when busy */
139static inline int i2c_busy(void)
140{
141 return (I2C2_SR & 1);
142}
143
144static 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
115static void ascodec_start_req(struct ascodec_request *req); 166 req->status = 1;
116static int ascodec_continue_req(struct ascodec_request *req, int irq_status);
117static void ascodec_finish_req(struct ascodec_request *req);
118 167
119void 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
180static 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
203static 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
127void INT_I2C_AUDIO(void) 228void 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 */ 311static void ascodec_req_init(struct ascodec_request *req, int type,
211static int i2c_busy(void)
212{
213 return (I2C2_SR & 1);
214}
215
216void 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
227void ascodec_submit(struct ascodec_request *req) 322static 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
244static 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
269static 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
292static 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
328static int irq_disabled(void) 339static 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 */
355void ascodec_async_write(unsigned int index, unsigned int value, 365static 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 */
385void ascodec_async_read(unsigned int index, unsigned int len, 394static 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
434static void ascodec_read_cb(unsigned const char *data, unsigned int len) 443static 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
484void 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
475void ascodec_wait_adc_finished(void) 492void ascodec_wait_adc_finished(void)
476{ 493{
477 wakeup_wait(&adc_wkup, TIMEOUT_BLOCK); 494 wakeup_wait(&adc_wkup, TIMEOUT_BLOCK);