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.c108
1 files changed, 105 insertions, 3 deletions
diff --git a/firmware/target/arm/as3525/ascodec-as3525.c b/firmware/target/arm/as3525/ascodec-as3525.c
index ca81d7842f..441008493c 100644
--- a/firmware/target/arm/as3525/ascodec-as3525.c
+++ b/firmware/target/arm/as3525/ascodec-as3525.c
@@ -50,6 +50,7 @@
50#include "system.h" 50#include "system.h"
51#include "as3525.h" 51#include "as3525.h"
52#include "i2c.h" 52#include "i2c.h"
53#include "usb-target.h"
53 54
54#define I2C2_DATA *((volatile unsigned int *)(I2C_AUDIO_BASE + 0x00)) 55#define I2C2_DATA *((volatile unsigned int *)(I2C_AUDIO_BASE + 0x00))
55#define I2C2_SLAD0 *((volatile unsigned int *)(I2C_AUDIO_BASE + 0x04)) 56#define I2C2_SLAD0 *((volatile unsigned int *)(I2C_AUDIO_BASE + 0x04))
@@ -81,15 +82,47 @@
81#define REQ_FINISHED 1 82#define REQ_FINISHED 1
82#define REQ_RETRY 2 83#define REQ_RETRY 2
83 84
85#ifdef DEBUG
86#define IFDEBUG(x) x
87#else
88#define IFDEBUG(x)
89#endif
90
84static struct mutex as_mtx; 91static struct mutex as_mtx;
85 92
93static int ascodec_enrd0_shadow = 0;
94
86static unsigned char *req_data_ptr = NULL; 95static unsigned char *req_data_ptr = NULL;
87static struct ascodec_request *req_head = NULL; 96static struct ascodec_request *req_head = NULL;
88static struct ascodec_request *req_tail = NULL; 97static struct ascodec_request *req_tail = NULL;
89 98
99static struct wakeup adc_wkup;
100
101#ifdef DEBUG
102static int int_audio_ctr = 0;
103static int int_chg_finished = 0;
104static int int_chg_insert = 0;
105static int int_chg_remove = 0;
106static int int_usb_insert = 0;
107static int int_usb_remove = 0;
108static int int_rtc = 0;
109static int int_adc = 0;
110#endif
111
112static struct ascodec_request as_audio_req;
113
90static void ascodec_start_req(struct ascodec_request *req); 114static void ascodec_start_req(struct ascodec_request *req);
91static int ascodec_continue_req(struct ascodec_request *req, int irq_status); 115static int ascodec_continue_req(struct ascodec_request *req, int irq_status);
92static void ascodec_finish_req(struct ascodec_request *req); 116static void ascodec_finish_req(struct ascodec_request *req);
117static void ascodec_read_cb(unsigned const char *data, unsigned int len);
118
119void INT_AUDIO(void)
120{
121 VIC_INT_EN_CLEAR = INTERRUPT_AUDIO;
122 IFDEBUG(int_audio_ctr++);
123
124 ascodec_async_read(AS3514_IRQ_ENRD0, 3, &as_audio_req, ascodec_read_cb);
125}
93 126
94void INT_I2C_AUDIO(void) 127void INT_I2C_AUDIO(void)
95{ 128{
@@ -129,6 +162,7 @@ void ascodec_init(void)
129 int prescaler; 162 int prescaler;
130 163
131 mutex_init(&as_mtx); 164 mutex_init(&as_mtx);
165 wakeup_init(&adc_wkup);
132 166
133 /* enable clock */ 167 /* enable clock */
134 CGU_PERI |= CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE; 168 CGU_PERI |= CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE;
@@ -145,9 +179,14 @@ void ascodec_init(void)
145 179
146 I2C2_IMR = 0x00; /* disable interrupts */ 180 I2C2_IMR = 0x00; /* disable interrupts */
147 I2C2_INT_CLR |= I2C2_RIS; /* clear interrupt status */ 181 I2C2_INT_CLR |= I2C2_RIS; /* clear interrupt status */
148 VIC_INT_ENABLE = INTERRUPT_I2C_AUDIO; 182 VIC_INT_ENABLE = INTERRUPT_I2C_AUDIO | INTERRUPT_AUDIO;
149}
150 183
184 /* Generate irq for usb+charge status change */
185 ascodec_write(AS3514_IRQ_ENRD0, /*IRQ_CHGSTAT |*/ IRQ_USBSTAT);
186 /* Generate irq for push-pull, active high, irq on rtc+adc change */
187 ascodec_write(AS3514_IRQ_ENRD2, IRQ_PUSHPULL | IRQ_HIGHACTIVE |
188 /*IRQ_RTC |*/ IRQ_ADC);
189}
151 190
152/* returns != 0 when busy */ 191/* returns != 0 when busy */
153static int i2c_busy(void) 192static int i2c_busy(void)
@@ -297,9 +336,18 @@ static void ascodec_wait(struct ascodec_request *req)
297void ascodec_async_write(unsigned int index, unsigned int value, 336void ascodec_async_write(unsigned int index, unsigned int value,
298 struct ascodec_request *req) 337 struct ascodec_request *req)
299{ 338{
300 if (index == AS3514_CVDD_DCDC3) { 339 switch(index) {
340 case AS3514_CVDD_DCDC3:
301 /* prevent setting of the LREG_CP_not bit */ 341 /* prevent setting of the LREG_CP_not bit */
302 value &= ~(1 << 5); 342 value &= ~(1 << 5);
343 break;
344 case AS3514_IRQ_ENRD0:
345 /* save value in register shadow
346 * for ascodec_(en|dis)able_endofch_irq() */
347 ascodec_enrd0_shadow = value;
348 break;
349 default:
350 break;
303 } 351 }
304 352
305 ascodec_req_init(req, ASCODEC_REQ_WRITE, index, 1); 353 ascodec_req_init(req, ASCODEC_REQ_WRITE, index, 1);
@@ -375,6 +423,60 @@ int ascodec_readbytes(unsigned int index, unsigned int len, unsigned char *data)
375 return i; 423 return i;
376} 424}
377 425
426static void ascodec_read_cb(unsigned const char *data, unsigned int len)
427{
428 if (len != 3) /* some error happened? */
429 return;
430
431 if (data[0] & CHG_ENDOFCH) { /* chg finished */
432 IFDEBUG(int_chg_finished++);
433 }
434 if (data[0] & CHG_CHANGED) { /* chg status changed */
435 if (data[0] & CHG_STATUS) {
436 IFDEBUG(int_chg_insert++);
437 } else {
438 IFDEBUG(int_chg_remove++);
439 }
440 }
441 if (data[0] & USB_CHANGED) { /* usb status changed */
442 if (data[0] & USB_STATUS) {
443 IFDEBUG(int_usb_insert++);
444 usb_insert_int();
445 } else {
446 IFDEBUG(int_usb_remove++);
447 usb_remove_int();
448 }
449 }
450 if (data[2] & IRQ_RTC) { /* rtc irq */
451 /*
452 * Can be configured for once per second or once per minute,
453 * default is once per second
454 */
455 IFDEBUG(int_rtc++);
456 }
457 if (data[2] & IRQ_ADC) { /* adc finished */
458 IFDEBUG(int_adc++);
459 wakeup_signal(&adc_wkup);
460 }
461 VIC_INT_ENABLE = INTERRUPT_AUDIO;
462}
463
464void ascodec_wait_adc_finished(void)
465{
466 wakeup_wait(&adc_wkup, TIMEOUT_BLOCK);
467}
468
469
470void ascodec_enable_endofch_irq(void)
471{
472 ascodec_write(AS3514_IRQ_ENRD0, ascodec_enrd0_shadow | CHG_ENDOFCH);
473}
474
475void ascodec_disable_endofch_irq(void)
476{
477 ascodec_write(AS3514_IRQ_ENRD0, ascodec_enrd0_shadow & ~CHG_ENDOFCH);
478}
479
378/* 480/*
379 * NOTE: 481 * NOTE:
380 * After the conversion to interrupts, ascodec_(lock|unlock) are only used by 482 * After the conversion to interrupts, ascodec_(lock|unlock) are only used by