summaryrefslogtreecommitdiff
path: root/firmware/target/arm/as3525/ascodec-as3525.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/as3525/ascodec-as3525.c')
-rw-r--r--firmware/target/arm/as3525/ascodec-as3525.c98
1 files changed, 68 insertions, 30 deletions
diff --git a/firmware/target/arm/as3525/ascodec-as3525.c b/firmware/target/arm/as3525/ascodec-as3525.c
index 87a1447c63..52d50ef077 100644
--- a/firmware/target/arm/as3525/ascodec-as3525.c
+++ b/firmware/target/arm/as3525/ascodec-as3525.c
@@ -185,10 +185,18 @@ void ascodec_init(void)
185 185
186 I2C2_IMR = 0x00; /* disable interrupts */ 186 I2C2_IMR = 0x00; /* disable interrupts */
187 I2C2_INT_CLR |= I2C2_RIS; /* clear interrupt status */ 187 I2C2_INT_CLR |= I2C2_RIS; /* clear interrupt status */
188 VIC_INT_ENABLE = INTERRUPT_I2C_AUDIO | INTERRUPT_AUDIO; 188 VIC_INT_ENABLE = INTERRUPT_I2C_AUDIO;
189#if CONFIG_CPU == AS3525 /* interrupts do not work correctly on as3525v2 */
190 VIC_INT_ENABLE = INTERRUPT_AUDIO;
191#endif
189 192
190 /* Generate irq for usb+charge status change */ 193 /* Generate irq for usb+charge status change */
191 ascodec_write(AS3514_IRQ_ENRD0, /*IRQ_CHGSTAT |*/ IRQ_USBSTAT); 194 ascodec_write(AS3514_IRQ_ENRD0,
195#ifdef CONFIG_CHARGING /* m200v4 can't charge */
196 IRQ_CHGSTAT | IRQ_ENDOFCH |
197#endif
198 IRQ_USBSTAT);
199
192 /* Generate irq for push-pull, active high, irq on rtc+adc change */ 200 /* Generate irq for push-pull, active high, irq on rtc+adc change */
193 ascodec_write(AS3514_IRQ_ENRD2, IRQ_PUSHPULL | IRQ_HIGHACTIVE | 201 ascodec_write(AS3514_IRQ_ENRD2, IRQ_PUSHPULL | IRQ_HIGHACTIVE |
194 /*IRQ_RTC |*/ IRQ_ADC); 202 /*IRQ_RTC |*/ IRQ_ADC);
@@ -342,19 +350,8 @@ static void ascodec_wait(struct ascodec_request *req)
342void ascodec_async_write(unsigned int index, unsigned int value, 350void ascodec_async_write(unsigned int index, unsigned int value,
343 struct ascodec_request *req) 351 struct ascodec_request *req)
344{ 352{
345 switch(index) { 353 if (index == AS3514_CVDD_DCDC3) /* prevent setting of the LREG_CP_not bit */
346 case AS3514_CVDD_DCDC3:
347 /* prevent setting of the LREG_CP_not bit */
348 value &= ~(1 << 5); 354 value &= ~(1 << 5);
349 break;
350 case AS3514_IRQ_ENRD0:
351 /* save value in register shadow
352 * for ascodec_(en|dis)able_endofch_irq() */
353 ascodec_enrd0_shadow = value;
354 break;
355 default:
356 break;
357 }
358 355
359 ascodec_req_init(req, ASCODEC_REQ_WRITE, index, 1); 356 ascodec_req_init(req, ASCODEC_REQ_WRITE, index, 1);
360 req->data[0] = value; 357 req->data[0] = value;
@@ -429,24 +426,37 @@ int ascodec_readbytes(unsigned int index, unsigned int len, unsigned char *data)
429 return i; 426 return i;
430} 427}
431 428
432#if CONFIG_CPU == AS3525 429/*
433static void ascodec_read_cb(unsigned const char *data, unsigned int len) 430 * Reading AS3514_IRQ_ENRD0 clears all interrupt bits, so we cache the results
431 * and clear individual bits when a specific interrupt is checked:
432 * - we clear the ENDOFCH (end of charge) interrupt when it's read
433 * - we set the usb and charger presence when the status change is detected
434 *
435 * on AS3525(v1) ENRD0 is only read in an interrupt handler
436 * on AS3525v2 the interrupt handler doesn't work (yet), so we read the register
437 * synchronously.
438 * - To avoid race conditions all the reads to this register must be atomic.
439 * We don't need to disable interrupts when reading it because all the reads
440 * (in powermgmt-ascodec.c and power-as3525.c) are performed by the same
441 * thread (the power thread).
442 */
443static void cache_enrd0(int enrd0)
434{ 444{
435 if (len != 3) /* some error happened? */ 445 if (enrd0 & CHG_ENDOFCH) { /* chg finished */
436 return; 446 ascodec_enrd0_shadow |= CHG_ENDOFCH;
437
438 if (data[0] & CHG_ENDOFCH) { /* chg finished */
439 IFDEBUG(int_chg_finished++); 447 IFDEBUG(int_chg_finished++);
440 } 448 }
441 if (data[0] & CHG_CHANGED) { /* chg status changed */ 449 if (enrd0 & CHG_CHANGED) { /* chg status changed */
442 if (data[0] & CHG_STATUS) { 450 if (enrd0 & CHG_STATUS) {
451 ascodec_enrd0_shadow |= CHG_STATUS;
443 IFDEBUG(int_chg_insert++); 452 IFDEBUG(int_chg_insert++);
444 } else { 453 } else {
454 ascodec_enrd0_shadow &= ~CHG_STATUS;
445 IFDEBUG(int_chg_remove++); 455 IFDEBUG(int_chg_remove++);
446 } 456 }
447 } 457 }
448 if (data[0] & USB_CHANGED) { /* usb status changed */ 458 if (enrd0 & USB_CHANGED) { /* usb status changed */
449 if (data[0] & USB_STATUS) { 459 if (enrd0 & USB_STATUS) {
450 IFDEBUG(int_usb_insert++); 460 IFDEBUG(int_usb_insert++);
451 usb_insert_int(); 461 usb_insert_int();
452 } else { 462 } else {
@@ -454,6 +464,16 @@ static void ascodec_read_cb(unsigned const char *data, unsigned int len)
454 usb_remove_int(); 464 usb_remove_int();
455 } 465 }
456 } 466 }
467}
468
469#if CONFIG_CPU == AS3525
470static void ascodec_read_cb(unsigned const char *data, unsigned int len)
471{
472 if (len != 3) /* some error happened? */
473 return;
474
475 cache_enrd0(data[0]);
476
457 if (data[2] & IRQ_RTC) { /* rtc irq */ 477 if (data[2] & IRQ_RTC) { /* rtc irq */
458 /* 478 /*
459 * Can be configured for once per second or once per minute, 479 * Can be configured for once per second or once per minute,
@@ -468,22 +488,40 @@ static void ascodec_read_cb(unsigned const char *data, unsigned int len)
468 VIC_INT_ENABLE = INTERRUPT_AUDIO; 488 VIC_INT_ENABLE = INTERRUPT_AUDIO;
469} 489}
470 490
491#endif /* CONFIG_CPU == AS3525 */
492
471void ascodec_wait_adc_finished(void) 493void ascodec_wait_adc_finished(void)
472{ 494{
495#if CONFIG_CPU == AS3525
473 wakeup_wait(&adc_wkup, TIMEOUT_BLOCK); 496 wakeup_wait(&adc_wkup, TIMEOUT_BLOCK);
497#else
498 /* no interrupts, busy wait
499 * XXX: make sure this is the only reader of IRQ_ENRD2
500 */
501 while(!(ascodec_read(AS3514_IRQ_ENRD2) & IRQ_ADC))
502 yield();
503#endif
474} 504}
475#endif /* CONFIG_CPU == AS3525 */
476
477 505
478void ascodec_enable_endofch_irq(void) 506#ifdef CONFIG_CHARGING
507bool ascodec_endofch(void)
479{ 508{
480 ascodec_write(AS3514_IRQ_ENRD0, ascodec_enrd0_shadow | CHG_ENDOFCH); 509#if CONFIG_CPU != AS3525
510 cache_enrd0(ascodec_read(AS3514_IRQ_ENRD0));
511#endif
512 bool ret = ascodec_enrd0_shadow & CHG_ENDOFCH;
513 ascodec_enrd0_shadow &= ~CHG_ENDOFCH; // clear interrupt
514 return ret;
481} 515}
482 516
483void ascodec_disable_endofch_irq(void) 517bool ascodec_chg_status(void)
484{ 518{
485 ascodec_write(AS3514_IRQ_ENRD0, ascodec_enrd0_shadow & ~CHG_ENDOFCH); 519#if CONFIG_CPU != AS3525
520 cache_enrd0(ascodec_read(AS3514_IRQ_ENRD0));
521#endif
522 return ascodec_enrd0_shadow & CHG_STATUS;
486} 523}
524#endif /* CONFIG_CHARGING */
487 525
488/* 526/*
489 * NOTE: 527 * NOTE: