diff options
Diffstat (limited to 'firmware/target/arm/as3525/ascodec-as3525.c')
-rw-r--r-- | firmware/target/arm/as3525/ascodec-as3525.c | 108 |
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 | |||
84 | static struct mutex as_mtx; | 91 | static struct mutex as_mtx; |
85 | 92 | ||
93 | static int ascodec_enrd0_shadow = 0; | ||
94 | |||
86 | static unsigned char *req_data_ptr = NULL; | 95 | static unsigned char *req_data_ptr = NULL; |
87 | static struct ascodec_request *req_head = NULL; | 96 | static struct ascodec_request *req_head = NULL; |
88 | static struct ascodec_request *req_tail = NULL; | 97 | static struct ascodec_request *req_tail = NULL; |
89 | 98 | ||
99 | static struct wakeup adc_wkup; | ||
100 | |||
101 | #ifdef DEBUG | ||
102 | static int int_audio_ctr = 0; | ||
103 | static int int_chg_finished = 0; | ||
104 | static int int_chg_insert = 0; | ||
105 | static int int_chg_remove = 0; | ||
106 | static int int_usb_insert = 0; | ||
107 | static int int_usb_remove = 0; | ||
108 | static int int_rtc = 0; | ||
109 | static int int_adc = 0; | ||
110 | #endif | ||
111 | |||
112 | static struct ascodec_request as_audio_req; | ||
113 | |||
90 | static void ascodec_start_req(struct ascodec_request *req); | 114 | static void ascodec_start_req(struct ascodec_request *req); |
91 | static int ascodec_continue_req(struct ascodec_request *req, int irq_status); | 115 | static int ascodec_continue_req(struct ascodec_request *req, int irq_status); |
92 | static void ascodec_finish_req(struct ascodec_request *req); | 116 | static void ascodec_finish_req(struct ascodec_request *req); |
117 | static void ascodec_read_cb(unsigned const char *data, unsigned int len); | ||
118 | |||
119 | void 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 | ||
94 | void INT_I2C_AUDIO(void) | 127 | void 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 */ |
153 | static int i2c_busy(void) | 192 | static int i2c_busy(void) |
@@ -297,9 +336,18 @@ static void ascodec_wait(struct ascodec_request *req) | |||
297 | void ascodec_async_write(unsigned int index, unsigned int value, | 336 | void 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 | ||
426 | static 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 | |||
464 | void ascodec_wait_adc_finished(void) | ||
465 | { | ||
466 | wakeup_wait(&adc_wkup, TIMEOUT_BLOCK); | ||
467 | } | ||
468 | |||
469 | |||
470 | void ascodec_enable_endofch_irq(void) | ||
471 | { | ||
472 | ascodec_write(AS3514_IRQ_ENRD0, ascodec_enrd0_shadow | CHG_ENDOFCH); | ||
473 | } | ||
474 | |||
475 | void 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 |