summaryrefslogtreecommitdiff
path: root/firmware/target
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target')
-rw-r--r--firmware/target/arm/adc-as3514.c12
-rw-r--r--firmware/target/arm/as3525/ascodec-as3525.c108
-rw-r--r--firmware/target/arm/as3525/ascodec-target.h8
-rw-r--r--firmware/target/arm/as3525/system-as3525.c1
-rw-r--r--firmware/target/arm/as3525/usb-as3525.c30
-rw-r--r--firmware/target/arm/as3525/usb-target.h29
-rw-r--r--firmware/target/arm/ascodec-target.h22
-rw-r--r--firmware/target/arm/powermgmt-ascodec.c8
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
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
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
69void ascodec_init(void); 69void ascodec_init(void);
70 70
71void ascodec_init_late(void);
72
71int ascodec_write(unsigned int index, unsigned int value); 73int ascodec_write(unsigned int index, unsigned int value);
72 74
73int ascodec_read(unsigned int index); 75int ascodec_read(unsigned int index);
@@ -102,4 +104,10 @@ void ascodec_lock(void);
102 104
103void ascodec_unlock(void); 105void ascodec_unlock(void);
104 106
107void ascodec_wait_adc_finished(void);
108
109void ascodec_enable_endofch_irq(void);
110
111void 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) 32static 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
42void usb_enable(bool on) 34void usb_enable(bool on)
43{ 35{
@@ -51,19 +43,21 @@ void usb_enable(bool on)
51#endif 43#endif
52} 44}
53 45
46void usb_insert_int(void)
47{
48 usb_status = USB_INSERTED;
49}
50
51void usb_remove_int(void)
52{
53 usb_status = USB_EXTRACTED;
54}
55
54void usb_init_device(void) 56void 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
61int usb_detect(void) 60int 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
24void usb_init_device(void);
25void usb_insert_int(void);
26void usb_remove_int(void);
27int 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
62static inline void ascodec_enable_endofch_irq(void)
63{
64 ascodec_write(AS3514_IRQ_ENRD0, IRQ_ENDOFCH);
65}
66
67static inline void ascodec_disable_endofch_irq(void)
68{
69 ascodec_write(AS3514_IRQ_ENRD0, 0);
70}
71
72static 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
62extern void ascodec_suppressor_on(bool on); 84extern 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. */
95static void disable_charger(void) 95static 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)
125void powermgmt_init_target(void) 125void 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}