diff options
Diffstat (limited to 'firmware/target/arm')
-rw-r--r-- | firmware/target/arm/adc-as3514.c | 12 | ||||
-rw-r--r-- | firmware/target/arm/as3525/ascodec-as3525.c | 108 | ||||
-rw-r--r-- | firmware/target/arm/as3525/ascodec-target.h | 8 | ||||
-rw-r--r-- | firmware/target/arm/as3525/system-as3525.c | 1 | ||||
-rw-r--r-- | firmware/target/arm/as3525/usb-as3525.c | 30 | ||||
-rw-r--r-- | firmware/target/arm/as3525/usb-target.h | 29 | ||||
-rw-r--r-- | firmware/target/arm/ascodec-target.h | 22 | ||||
-rw-r--r-- | firmware/target/arm/powermgmt-ascodec.c | 8 |
8 files changed, 193 insertions, 25 deletions
diff --git a/firmware/target/arm/adc-as3514.c b/firmware/target/arm/adc-as3514.c index 9c2a421441..77d65455fb 100644 --- a/firmware/target/arm/adc-as3514.c +++ b/firmware/target/arm/adc-as3514.c | |||
@@ -37,6 +37,18 @@ unsigned short adc_read(int channel) | |||
37 | { | 37 | { |
38 | unsigned char buf[2]; | 38 | unsigned char buf[2]; |
39 | 39 | ||
40 | /* | ||
41 | * The AS3514 ADC will trigger an interrupt when the conversion | ||
42 | * is finished, if the corresponding enable bit in IRQ_ENRD2 | ||
43 | * is set. | ||
44 | * Previously the code did not wait and this apparently did | ||
45 | * not pose any problems, but this should be more correct. | ||
46 | * Without the wait the data read back may be completely or | ||
47 | * partially (first one of the two bytes) stale. | ||
48 | */ | ||
49 | ascodec_wait_adc_finished(); | ||
50 | |||
51 | |||
40 | /* Read data */ | 52 | /* Read data */ |
41 | if (ascodec_readbytes(AS3514_ADC_0, 2, buf) >= 0) | 53 | if (ascodec_readbytes(AS3514_ADC_0, 2, buf) >= 0) |
42 | { | 54 | { |
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 |
diff --git a/firmware/target/arm/as3525/ascodec-target.h b/firmware/target/arm/as3525/ascodec-target.h index 4b110412c1..13946099c0 100644 --- a/firmware/target/arm/as3525/ascodec-target.h +++ b/firmware/target/arm/as3525/ascodec-target.h | |||
@@ -68,6 +68,8 @@ struct ascodec_request { | |||
68 | 68 | ||
69 | void ascodec_init(void); | 69 | void ascodec_init(void); |
70 | 70 | ||
71 | void ascodec_init_late(void); | ||
72 | |||
71 | int ascodec_write(unsigned int index, unsigned int value); | 73 | int ascodec_write(unsigned int index, unsigned int value); |
72 | 74 | ||
73 | int ascodec_read(unsigned int index); | 75 | int ascodec_read(unsigned int index); |
@@ -102,4 +104,10 @@ void ascodec_lock(void); | |||
102 | 104 | ||
103 | void ascodec_unlock(void); | 105 | void ascodec_unlock(void); |
104 | 106 | ||
107 | void ascodec_wait_adc_finished(void); | ||
108 | |||
109 | void ascodec_enable_endofch_irq(void); | ||
110 | |||
111 | void ascodec_disable_endofch_irq(void); | ||
112 | |||
105 | #endif /* !_ASCODEC_TARGET_H */ | 113 | #endif /* !_ASCODEC_TARGET_H */ |
diff --git a/firmware/target/arm/as3525/system-as3525.c b/firmware/target/arm/as3525/system-as3525.c index 4ee3e594a5..4e1714b8aa 100644 --- a/firmware/target/arm/as3525/system-as3525.c +++ b/firmware/target/arm/as3525/system-as3525.c | |||
@@ -112,6 +112,7 @@ struct vec_int_src vec_int_srcs[] = | |||
112 | { INT_SRC_DMAC, INT_DMAC }, | 112 | { INT_SRC_DMAC, INT_DMAC }, |
113 | { INT_SRC_NAND, INT_NAND }, | 113 | { INT_SRC_NAND, INT_NAND }, |
114 | { INT_SRC_I2C_AUDIO, INT_I2C_AUDIO }, | 114 | { INT_SRC_I2C_AUDIO, INT_I2C_AUDIO }, |
115 | { INT_SRC_AUDIO, INT_AUDIO }, | ||
115 | #ifdef HAVE_MULTIDRIVE | 116 | #ifdef HAVE_MULTIDRIVE |
116 | { INT_SRC_MCI0, INT_MCI0 }, | 117 | { INT_SRC_MCI0, INT_MCI0 }, |
117 | #endif | 118 | #endif |
diff --git a/firmware/target/arm/as3525/usb-as3525.c b/firmware/target/arm/as3525/usb-as3525.c index d5535d00b8..65edb598a3 100644 --- a/firmware/target/arm/as3525/usb-as3525.c +++ b/firmware/target/arm/as3525/usb-as3525.c | |||
@@ -29,15 +29,7 @@ | |||
29 | #include "power.h" | 29 | #include "power.h" |
30 | #include "as3525.h" | 30 | #include "as3525.h" |
31 | 31 | ||
32 | #if defined(SANSA_CLIP) | 32 | static int usb_status = USB_EXTRACTED; |
33 | #define USB_DETECT_PIN 6 | ||
34 | |||
35 | #elif defined(SANSA_FUZE) || defined(SANSA_E200V2) | ||
36 | #define USB_DETECT_PIN 3 | ||
37 | |||
38 | #elif defined(SANSA_C200V2) | ||
39 | #define USB_DETECT_PIN 1 | ||
40 | #endif | ||
41 | 33 | ||
42 | void usb_enable(bool on) | 34 | void usb_enable(bool on) |
43 | { | 35 | { |
@@ -51,19 +43,21 @@ void usb_enable(bool on) | |||
51 | #endif | 43 | #endif |
52 | } | 44 | } |
53 | 45 | ||
46 | void usb_insert_int(void) | ||
47 | { | ||
48 | usb_status = USB_INSERTED; | ||
49 | } | ||
50 | |||
51 | void usb_remove_int(void) | ||
52 | { | ||
53 | usb_status = USB_EXTRACTED; | ||
54 | } | ||
55 | |||
54 | void usb_init_device(void) | 56 | void usb_init_device(void) |
55 | { | 57 | { |
56 | #ifdef USB_DETECT_PIN | ||
57 | GPIOA_DIR &= ~(1 << USB_DETECT_PIN); /* set as input */ | ||
58 | #endif | ||
59 | } | 58 | } |
60 | 59 | ||
61 | int usb_detect(void) | 60 | int usb_detect(void) |
62 | { | 61 | { |
63 | #ifdef USB_DETECT_PIN | 62 | return usb_status; |
64 | if (GPIOA_PIN( USB_DETECT_PIN )) | ||
65 | return USB_INSERTED; | ||
66 | else | ||
67 | #endif | ||
68 | return USB_EXTRACTED; | ||
69 | } | 63 | } |
diff --git a/firmware/target/arm/as3525/usb-target.h b/firmware/target/arm/as3525/usb-target.h new file mode 100644 index 0000000000..55a7d87857 --- /dev/null +++ b/firmware/target/arm/as3525/usb-target.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Barry Wardelll | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef USB_TARGET_H | ||
22 | #define USB_TARGET_H | ||
23 | |||
24 | void usb_init_device(void); | ||
25 | void usb_insert_int(void); | ||
26 | void usb_remove_int(void); | ||
27 | int usb_detect(void); | ||
28 | |||
29 | #endif | ||
diff --git a/firmware/target/arm/ascodec-target.h b/firmware/target/arm/ascodec-target.h index d3a0bc4b7d..c87d869ebb 100644 --- a/firmware/target/arm/ascodec-target.h +++ b/firmware/target/arm/ascodec-target.h | |||
@@ -59,6 +59,28 @@ static inline void ascodec_unlock(void) | |||
59 | i2c_unlock(); | 59 | i2c_unlock(); |
60 | } | 60 | } |
61 | 61 | ||
62 | static inline void ascodec_enable_endofch_irq(void) | ||
63 | { | ||
64 | ascodec_write(AS3514_IRQ_ENRD0, IRQ_ENDOFCH); | ||
65 | } | ||
66 | |||
67 | static inline void ascodec_disable_endofch_irq(void) | ||
68 | { | ||
69 | ascodec_write(AS3514_IRQ_ENRD0, 0); | ||
70 | } | ||
71 | |||
72 | static inline void ascodec_wait_adc_finished(void) | ||
73 | { | ||
74 | /* | ||
75 | * FIXME: not implemented | ||
76 | * | ||
77 | * If irqs are not available on the target platform, | ||
78 | * this should be most likely implemented by polling | ||
79 | * AS3514_IRQ_ENRD2 in the same way powermgmt-ascodec.c | ||
80 | * is polling IRQ_ENDOFCH. | ||
81 | */ | ||
82 | } | ||
83 | |||
62 | extern void ascodec_suppressor_on(bool on); | 84 | extern void ascodec_suppressor_on(bool on); |
63 | 85 | ||
64 | #endif /* CPU_PP */ | 86 | #endif /* CPU_PP */ |
diff --git a/firmware/target/arm/powermgmt-ascodec.c b/firmware/target/arm/powermgmt-ascodec.c index 1eaaf6ab30..b463486346 100644 --- a/firmware/target/arm/powermgmt-ascodec.c +++ b/firmware/target/arm/powermgmt-ascodec.c | |||
@@ -94,7 +94,7 @@ static void battery_voltage_sync(void) | |||
94 | /* Disable charger and minimize all settings. Reset timers, etc. */ | 94 | /* Disable charger and minimize all settings. Reset timers, etc. */ |
95 | static void disable_charger(void) | 95 | static void disable_charger(void) |
96 | { | 96 | { |
97 | ascodec_write(AS3514_IRQ_ENRD0, 0); | 97 | ascodec_disable_endofch_irq(); |
98 | ascodec_write(AS3514_CHARGER, | 98 | ascodec_write(AS3514_CHARGER, |
99 | TMPSUP_OFF | CHG_I_50MA | CHG_V_3_90V | CHG_OFF); | 99 | TMPSUP_OFF | CHG_I_50MA | CHG_V_3_90V | CHG_OFF); |
100 | 100 | ||
@@ -111,11 +111,11 @@ static void enable_charger(void) | |||
111 | ascodec_write(AS3514_CHARGER, BATT_CHG_I | BATT_CHG_V); | 111 | ascodec_write(AS3514_CHARGER, BATT_CHG_I | BATT_CHG_V); |
112 | /* Watch for end of charge. Temperature supervision is handled in | 112 | /* Watch for end of charge. Temperature supervision is handled in |
113 | * hardware. Charger status can be read and has no interrupt enable. */ | 113 | * hardware. Charger status can be read and has no interrupt enable. */ |
114 | ascodec_write(AS3514_IRQ_ENRD0, CHG_ENDOFCH); | 114 | ascodec_enable_endofch_irq(); |
115 | 115 | ||
116 | sleep(HZ/10); /* Allow charger turn-on time (it could be gradual). */ | 116 | sleep(HZ/10); /* Allow charger turn-on time (it could be gradual). */ |
117 | 117 | ||
118 | ascodec_read(AS3514_IRQ_ENRD0); /* Clear out interrupts (important!) */ | 118 | ascodec_disable_endofch_irq(); |
119 | 119 | ||
120 | charge_state = CHARGING; | 120 | charge_state = CHARGING; |
121 | charger_total_timer = CHARGER_TOTAL_TIMER; | 121 | charger_total_timer = CHARGER_TOTAL_TIMER; |
@@ -125,7 +125,7 @@ static void enable_charger(void) | |||
125 | void powermgmt_init_target(void) | 125 | void powermgmt_init_target(void) |
126 | { | 126 | { |
127 | /* Everything CHARGER, OFF! */ | 127 | /* Everything CHARGER, OFF! */ |
128 | ascodec_write(AS3514_IRQ_ENRD0, 0); | 128 | ascodec_disable_endofch_irq(); |
129 | ascodec_write(AS3514_CHARGER, | 129 | ascodec_write(AS3514_CHARGER, |
130 | TMPSUP_OFF | CHG_I_50MA | CHG_V_3_90V | CHG_OFF); | 130 | TMPSUP_OFF | CHG_I_50MA | CHG_V_3_90V | CHG_OFF); |
131 | } | 131 | } |