diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/target/arm/as3525/ascodec-as3525.c | 70 |
1 files changed, 16 insertions, 54 deletions
diff --git a/firmware/target/arm/as3525/ascodec-as3525.c b/firmware/target/arm/as3525/ascodec-as3525.c index adc9b7f9a8..708215deed 100644 --- a/firmware/target/arm/as3525/ascodec-as3525.c +++ b/firmware/target/arm/as3525/ascodec-as3525.c | |||
@@ -96,7 +96,6 @@ static unsigned char *req_data_ptr = NULL; | |||
96 | static struct ascodec_request *req_head = NULL; | 96 | static struct ascodec_request *req_head = NULL; |
97 | static struct ascodec_request *req_tail = NULL; | 97 | static struct ascodec_request *req_tail = NULL; |
98 | 98 | ||
99 | #if CONFIG_CPU == AS3525 | ||
100 | static struct wakeup adc_wkup; | 99 | static struct wakeup adc_wkup; |
101 | static struct ascodec_request as_audio_req; | 100 | static struct ascodec_request as_audio_req; |
102 | 101 | ||
@@ -112,13 +111,11 @@ static int int_adc = 0; | |||
112 | #endif /* DEBUG */ | 111 | #endif /* DEBUG */ |
113 | 112 | ||
114 | static void ascodec_read_cb(unsigned const char *data, unsigned int len); | 113 | static void ascodec_read_cb(unsigned const char *data, unsigned int len); |
115 | #endif /* CONFIG_CPU == AS3525 */ | ||
116 | 114 | ||
117 | static void ascodec_start_req(struct ascodec_request *req); | 115 | static void ascodec_start_req(struct ascodec_request *req); |
118 | static int ascodec_continue_req(struct ascodec_request *req, int irq_status); | 116 | static int ascodec_continue_req(struct ascodec_request *req, int irq_status); |
119 | static void ascodec_finish_req(struct ascodec_request *req); | 117 | static void ascodec_finish_req(struct ascodec_request *req); |
120 | 118 | ||
121 | #if CONFIG_CPU == AS3525 | ||
122 | void INT_AUDIO(void) | 119 | void INT_AUDIO(void) |
123 | { | 120 | { |
124 | VIC_INT_EN_CLEAR = INTERRUPT_AUDIO; | 121 | VIC_INT_EN_CLEAR = INTERRUPT_AUDIO; |
@@ -126,7 +123,6 @@ void INT_AUDIO(void) | |||
126 | 123 | ||
127 | ascodec_async_read(AS3514_IRQ_ENRD0, 3, &as_audio_req, ascodec_read_cb); | 124 | ascodec_async_read(AS3514_IRQ_ENRD0, 3, &as_audio_req, ascodec_read_cb); |
128 | } | 125 | } |
129 | #endif /* CONFIG_CPU == AS3525 */ | ||
130 | 126 | ||
131 | void INT_I2C_AUDIO(void) | 127 | void INT_I2C_AUDIO(void) |
132 | { | 128 | { |
@@ -166,9 +162,7 @@ void ascodec_init(void) | |||
166 | int prescaler; | 162 | int prescaler; |
167 | 163 | ||
168 | mutex_init(&as_mtx); | 164 | mutex_init(&as_mtx); |
169 | #if CONFIG_CPU == AS3525 | ||
170 | wakeup_init(&adc_wkup); | 165 | wakeup_init(&adc_wkup); |
171 | #endif | ||
172 | 166 | ||
173 | /* enable clock */ | 167 | /* enable clock */ |
174 | CGU_PERI |= CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE; | 168 | CGU_PERI |= CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE; |
@@ -186,9 +180,7 @@ void ascodec_init(void) | |||
186 | I2C2_IMR = 0x00; /* disable interrupts */ | 180 | I2C2_IMR = 0x00; /* disable interrupts */ |
187 | I2C2_INT_CLR |= I2C2_RIS; /* clear interrupt status */ | 181 | I2C2_INT_CLR |= I2C2_RIS; /* clear interrupt status */ |
188 | VIC_INT_ENABLE = INTERRUPT_I2C_AUDIO; | 182 | VIC_INT_ENABLE = INTERRUPT_I2C_AUDIO; |
189 | #if CONFIG_CPU == AS3525 /* interrupts do not work correctly on as3525v2 */ | ||
190 | VIC_INT_ENABLE = INTERRUPT_AUDIO; | 183 | VIC_INT_ENABLE = INTERRUPT_AUDIO; |
191 | #endif | ||
192 | 184 | ||
193 | /* detect if USB was connected at startup since there is no transition */ | 185 | /* detect if USB was connected at startup since there is no transition */ |
194 | if(ascodec_read(AS3514_IRQ_ENRD0) & USB_STATUS) | 186 | if(ascodec_read(AS3514_IRQ_ENRD0) & USB_STATUS) |
@@ -203,9 +195,16 @@ void ascodec_init(void) | |||
203 | #endif | 195 | #endif |
204 | IRQ_USBSTAT); | 196 | IRQ_USBSTAT); |
205 | 197 | ||
198 | #if CONFIG_CPU == AS3525v2 | ||
199 | /* XIRQ = IRQ, active low reset signal, 6mA push-pull output */ | ||
200 | ascodec_write_pmu(0x1a, 3, (1<<2)|3); /* 1A-3 = Out_Cntr3 register */ | ||
201 | /* Generate irq on (rtc,) adc change */ | ||
202 | ascodec_write(AS3514_IRQ_ENRD2, /*IRQ_RTC |*/ IRQ_ADC); | ||
203 | #else | ||
206 | /* Generate irq for push-pull, active high, irq on rtc+adc change */ | 204 | /* Generate irq for push-pull, active high, irq on rtc+adc change */ |
207 | ascodec_write(AS3514_IRQ_ENRD2, IRQ_PUSHPULL | IRQ_HIGHACTIVE | | 205 | ascodec_write(AS3514_IRQ_ENRD2, IRQ_PUSHPULL | IRQ_HIGHACTIVE | |
208 | /*IRQ_RTC |*/ IRQ_ADC); | 206 | /*IRQ_RTC |*/ IRQ_ADC); |
207 | #endif | ||
209 | } | 208 | } |
210 | 209 | ||
211 | /* returns != 0 when busy */ | 210 | /* returns != 0 when busy */ |
@@ -432,28 +431,17 @@ int ascodec_readbytes(unsigned int index, unsigned int len, unsigned char *data) | |||
432 | return i; | 431 | return i; |
433 | } | 432 | } |
434 | 433 | ||
435 | /* | 434 | static void ascodec_read_cb(unsigned const char *data, unsigned int len) |
436 | * Reading AS3514_IRQ_ENRD0 clears all interrupt bits, so we cache the results | ||
437 | * and clear individual bits when a specific interrupt is checked: | ||
438 | * - we clear the ENDOFCH (end of charge) interrupt when it's read | ||
439 | * - we set the usb and charger presence when the status change is detected | ||
440 | * | ||
441 | * on AS3525(v1) ENRD0 is only read in an interrupt handler | ||
442 | * on AS3525v2 the interrupt handler doesn't work (yet), so we read the register | ||
443 | * synchronously. | ||
444 | * - To avoid race conditions all the reads to this register must be atomic. | ||
445 | * We don't need to disable interrupts when reading it because all the reads | ||
446 | * (in powermgmt-ascodec.c and power-as3525.c) are performed by the same | ||
447 | * thread (the power thread). | ||
448 | */ | ||
449 | static void cache_enrd0(int enrd0) | ||
450 | { | 435 | { |
451 | if (enrd0 & CHG_ENDOFCH) { /* chg finished */ | 436 | if (len != 3) /* some error happened? */ |
437 | return; | ||
438 | |||
439 | if (data[0] & CHG_ENDOFCH) { /* chg finished */ | ||
452 | ascodec_enrd0_shadow |= CHG_ENDOFCH; | 440 | ascodec_enrd0_shadow |= CHG_ENDOFCH; |
453 | IFDEBUG(int_chg_finished++); | 441 | IFDEBUG(int_chg_finished++); |
454 | } | 442 | } |
455 | if (enrd0 & CHG_CHANGED) { /* chg status changed */ | 443 | if (data[0] & CHG_CHANGED) { /* chg status changed */ |
456 | if (enrd0 & CHG_STATUS) { | 444 | if (data[0] & CHG_STATUS) { |
457 | ascodec_enrd0_shadow |= CHG_STATUS; | 445 | ascodec_enrd0_shadow |= CHG_STATUS; |
458 | IFDEBUG(int_chg_insert++); | 446 | IFDEBUG(int_chg_insert++); |
459 | } else { | 447 | } else { |
@@ -461,8 +449,8 @@ static void cache_enrd0(int enrd0) | |||
461 | IFDEBUG(int_chg_remove++); | 449 | IFDEBUG(int_chg_remove++); |
462 | } | 450 | } |
463 | } | 451 | } |
464 | if (enrd0 & USB_CHANGED) { /* usb status changed */ | 452 | if (data[0] & USB_CHANGED) { /* usb status changed */ |
465 | if (enrd0 & USB_STATUS) { | 453 | if (data[0] & USB_STATUS) { |
466 | IFDEBUG(int_usb_insert++); | 454 | IFDEBUG(int_usb_insert++); |
467 | usb_insert_int(); | 455 | usb_insert_int(); |
468 | } else { | 456 | } else { |
@@ -470,16 +458,6 @@ static void cache_enrd0(int enrd0) | |||
470 | usb_remove_int(); | 458 | usb_remove_int(); |
471 | } | 459 | } |
472 | } | 460 | } |
473 | } | ||
474 | |||
475 | #if CONFIG_CPU == AS3525 | ||
476 | static void ascodec_read_cb(unsigned const char *data, unsigned int len) | ||
477 | { | ||
478 | if (len != 3) /* some error happened? */ | ||
479 | return; | ||
480 | |||
481 | cache_enrd0(data[0]); | ||
482 | |||
483 | if (data[2] & IRQ_RTC) { /* rtc irq */ | 461 | if (data[2] & IRQ_RTC) { /* rtc irq */ |
484 | /* | 462 | /* |
485 | * Can be configured for once per second or once per minute, | 463 | * Can be configured for once per second or once per minute, |
@@ -494,27 +472,14 @@ static void ascodec_read_cb(unsigned const char *data, unsigned int len) | |||
494 | VIC_INT_ENABLE = INTERRUPT_AUDIO; | 472 | VIC_INT_ENABLE = INTERRUPT_AUDIO; |
495 | } | 473 | } |
496 | 474 | ||
497 | #endif /* CONFIG_CPU == AS3525 */ | ||
498 | |||
499 | void ascodec_wait_adc_finished(void) | 475 | void ascodec_wait_adc_finished(void) |
500 | { | 476 | { |
501 | #if CONFIG_CPU == AS3525 | ||
502 | wakeup_wait(&adc_wkup, TIMEOUT_BLOCK); | 477 | wakeup_wait(&adc_wkup, TIMEOUT_BLOCK); |
503 | #else | ||
504 | /* no interrupts, busy wait | ||
505 | * XXX: make sure this is the only reader of IRQ_ENRD2 | ||
506 | */ | ||
507 | while(!(ascodec_read(AS3514_IRQ_ENRD2) & IRQ_ADC)) | ||
508 | yield(); | ||
509 | #endif | ||
510 | } | 478 | } |
511 | 479 | ||
512 | #ifdef CONFIG_CHARGING | 480 | #ifdef CONFIG_CHARGING |
513 | bool ascodec_endofch(void) | 481 | bool ascodec_endofch(void) |
514 | { | 482 | { |
515 | #if CONFIG_CPU != AS3525 | ||
516 | cache_enrd0(ascodec_read(AS3514_IRQ_ENRD0)); | ||
517 | #endif | ||
518 | bool ret = ascodec_enrd0_shadow & CHG_ENDOFCH; | 483 | bool ret = ascodec_enrd0_shadow & CHG_ENDOFCH; |
519 | ascodec_enrd0_shadow &= ~CHG_ENDOFCH; // clear interrupt | 484 | ascodec_enrd0_shadow &= ~CHG_ENDOFCH; // clear interrupt |
520 | return ret; | 485 | return ret; |
@@ -522,9 +487,6 @@ bool ascodec_endofch(void) | |||
522 | 487 | ||
523 | bool ascodec_chg_status(void) | 488 | bool ascodec_chg_status(void) |
524 | { | 489 | { |
525 | #if CONFIG_CPU != AS3525 | ||
526 | cache_enrd0(ascodec_read(AS3514_IRQ_ENRD0)); | ||
527 | #endif | ||
528 | return ascodec_enrd0_shadow & CHG_STATUS; | 490 | return ascodec_enrd0_shadow & CHG_STATUS; |
529 | } | 491 | } |
530 | #endif /* CONFIG_CHARGING */ | 492 | #endif /* CONFIG_CHARGING */ |