summaryrefslogtreecommitdiffstats
path: root/firmware
diff options
context:
space:
mode:
authorTobias Diedrich <ranma+coreboot@tdiedrich.de>2010-03-23 05:02:37 +0000
committerTobias Diedrich <ranma+coreboot@tdiedrich.de>2010-03-23 05:02:37 +0000
commit47ab95904efe238568e4cc66f0d3aacd9e7a8c10 (patch)
tree8da94d74b9e0ef3ad01011d706781577eeec0e26 /firmware
parent655034983547c0678842e7407cebe0ea12b006cc (diff)
downloadrockbox-47ab95904efe238568e4cc66f0d3aacd9e7a8c10.tar.gz
rockbox-47ab95904efe238568e4cc66f0d3aacd9e7a8c10.tar.bz2
rockbox-47ab95904efe238568e4cc66f0d3aacd9e7a8c10.zip
Add handler for audio irq.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25299 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r--firmware/export/as3514.h15
-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
9 files changed, 208 insertions, 25 deletions
diff --git a/firmware/export/as3514.h b/firmware/export/as3514.h
index a9b12de36e..39a99415b6 100644
--- a/firmware/export/as3514.h
+++ b/firmware/export/as3514.h
@@ -283,6 +283,21 @@ extern void audiohw_set_lineout_vol(int vol_l, int vol_r);
#define RVDD_WASLOW (0x1 << 1)
#define BVDD_ISLOW (0x1 << 0)
+#define IRQ_ENDOFCH (0x1 << 6)
+#define IRQ_CHGSTAT (0x1 << 4)
+#define IRQ_USBSTAT (0x1 << 2)
+
+/* AS3514_IRQ_ENRD2 */
+#define DEBOUNCE_128MS (0x2 << 6)
+#define DEBOUNCE_256MS (0x1 << 6)
+#define DEBOUNCE_512MS (0x0 << 6)
+#define IRQ_HIGHACTIVE (0x1 << 5)
+#define IRQ_PUSHPULL (0x1 << 4)
+#define IRQ_REMDET2 (0x1 << 3)
+#define IRQ_REMDET1 (0x1 << 2)
+#define IRQ_RTC (0x1 << 1)
+#define IRQ_ADC (0x1 << 0)
+
#define AS3514_I2C_ADDR 0x46
#endif /* _AS3514_H */
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)
{
unsigned char buf[2];
+ /*
+ * The AS3514 ADC will trigger an interrupt when the conversion
+ * is finished, if the corresponding enable bit in IRQ_ENRD2
+ * is set.
+ * Previously the code did not wait and this apparently did
+ * not pose any problems, but this should be more correct.
+ * Without the wait the data read back may be completely or
+ * partially (first one of the two bytes) stale.
+ */
+ ascodec_wait_adc_finished();
+
+
/* Read data */
if (ascodec_readbytes(AS3514_ADC_0, 2, buf) >= 0)
{
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 @@
#include "system.h"
#include "as3525.h"
#include "i2c.h"
+#include "usb-target.h"
#define I2C2_DATA *((volatile unsigned int *)(I2C_AUDIO_BASE + 0x00))
#define I2C2_SLAD0 *((volatile unsigned int *)(I2C_AUDIO_BASE + 0x04))
@@ -81,15 +82,47 @@
#define REQ_FINISHED 1
#define REQ_RETRY 2
+#ifdef DEBUG
+#define IFDEBUG(x) x
+#else
+#define IFDEBUG(x)
+#endif
+
static struct mutex as_mtx;
+static int ascodec_enrd0_shadow = 0;
+
static unsigned char *req_data_ptr = NULL;
static struct ascodec_request *req_head = NULL;
static struct ascodec_request *req_tail = NULL;
+static struct wakeup adc_wkup;
+
+#ifdef DEBUG
+static int int_audio_ctr = 0;
+static int int_chg_finished = 0;
+static int int_chg_insert = 0;
+static int int_chg_remove = 0;
+static int int_usb_insert = 0;
+static int int_usb_remove = 0;
+static int int_rtc = 0;
+static int int_adc = 0;
+#endif
+
+static struct ascodec_request as_audio_req;
+
static void ascodec_start_req(struct ascodec_request *req);
static int ascodec_continue_req(struct ascodec_request *req, int irq_status);
static void ascodec_finish_req(struct ascodec_request *req);
+static void ascodec_read_cb(unsigned const char *data, unsigned int len);
+
+void INT_AUDIO(void)
+{
+ VIC_INT_EN_CLEAR = INTERRUPT_AUDIO;
+ IFDEBUG(int_audio_ctr++);
+
+ ascodec_async_read(AS3514_IRQ_ENRD0, 3, &as_audio_req, ascodec_read_cb);
+}
void INT_I2C_AUDIO(void)
{
@@ -129,6 +162,7 @@ void ascodec_init(void)
int prescaler;
mutex_init(&as_mtx);
+ wakeup_init(&adc_wkup);
/* enable clock */
CGU_PERI |= CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE;
@@ -145,9 +179,14 @@ void ascodec_init(void)
I2C2_IMR = 0x00; /* disable interrupts */
I2C2_INT_CLR |= I2C2_RIS; /* clear interrupt status */
- VIC_INT_ENABLE = INTERRUPT_I2C_AUDIO;
-}
+ VIC_INT_ENABLE = INTERRUPT_I2C_AUDIO | INTERRUPT_AUDIO;
+ /* Generate irq for usb+charge status change */
+ ascodec_write(AS3514_IRQ_ENRD0, /*IRQ_CHGSTAT |*/ IRQ_USBSTAT);
+ /* Generate irq for push-pull, active high, irq on rtc+adc change */
+ ascodec_write(AS3514_IRQ_ENRD2, IRQ_PUSHPULL | IRQ_HIGHACTIVE |
+ /*IRQ_RTC |*/ IRQ_ADC);
+}
/* returns != 0 when busy */
static int i2c_busy(void)
@@ -297,9 +336,18 @@ static void ascodec_wait(struct ascodec_request *req)
void ascodec_async_write(unsigned int index, unsigned int value,
struct ascodec_request *req)
{
- if (index == AS3514_CVDD_DCDC3) {
+ switch(index) {
+ case AS3514_CVDD_DCDC3:
/* prevent setting of the LREG_CP_not bit */
value &= ~(1 << 5);
+ break;
+ case AS3514_IRQ_ENRD0:
+ /* save value in register shadow
+ * for ascodec_(en|dis)able_endofch_irq() */
+ ascodec_enrd0_shadow = value;
+ break;
+ default:
+ break;
}
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)
return i;
}
+static void ascodec_read_cb(unsigned const char *data, unsigned int len)
+{
+ if (len != 3) /* some error happened? */
+ return;
+
+ if (data[0] & CHG_ENDOFCH) { /* chg finished */
+ IFDEBUG(int_chg_finished++);
+ }
+ if (data[0] & CHG_CHANGED) { /* chg status changed */
+ if (data[0] & CHG_STATUS) {
+ IFDEBUG(int_chg_insert++);
+ } else {
+ IFDEBUG(int_chg_remove++);
+ }
+ }
+ if (data[0] & USB_CHANGED) { /* usb status changed */
+ if (data[0] & USB_STATUS) {
+ IFDEBUG(int_usb_insert++);
+ usb_insert_int();
+ } else {
+ IFDEBUG(int_usb_remove++);
+ usb_remove_int();
+ }
+ }
+ if (data[2] & IRQ_RTC) { /* rtc irq */
+ /*
+ * Can be configured for once per second or once per minute,
+ * default is once per second
+ */
+ IFDEBUG(int_rtc++);
+ }
+ if (data[2] & IRQ_ADC) { /* adc finished */
+ IFDEBUG(int_adc++);
+ wakeup_signal(&adc_wkup);
+ }
+ VIC_INT_ENABLE = INTERRUPT_AUDIO;
+}
+
+void ascodec_wait_adc_finished(void)
+{
+ wakeup_wait(&adc_wkup, TIMEOUT_BLOCK);
+}
+
+
+void ascodec_enable_endofch_irq(void)
+{
+ ascodec_write(AS3514_IRQ_ENRD0, ascodec_enrd0_shadow | CHG_ENDOFCH);
+}
+
+void ascodec_disable_endofch_irq(void)
+{
+ ascodec_write(AS3514_IRQ_ENRD0, ascodec_enrd0_shadow & ~CHG_ENDOFCH);
+}
+
/*
* NOTE:
* 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 {
void ascodec_init(void);
+void ascodec_init_late(void);
+
int ascodec_write(unsigned int index, unsigned int value);
int ascodec_read(unsigned int index);
@@ -102,4 +104,10 @@ void ascodec_lock(void);
void ascodec_unlock(void);
+void ascodec_wait_adc_finished(void);
+
+void ascodec_enable_endofch_irq(void);
+
+void ascodec_disable_endofch_irq(void);
+
#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[] =
{ INT_SRC_DMAC, INT_DMAC },
{ INT_SRC_NAND, INT_NAND },
{ INT_SRC_I2C_AUDIO, INT_I2C_AUDIO },
+ { INT_SRC_AUDIO, INT_AUDIO },
#ifdef HAVE_MULTIDRIVE
{ INT_SRC_MCI0, INT_MCI0 },
#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 @@
#include "power.h"
#include "as3525.h"
-#if defined(SANSA_CLIP)
-#define USB_DETECT_PIN 6
-
-#elif defined(SANSA_FUZE) || defined(SANSA_E200V2)
-#define USB_DETECT_PIN 3
-
-#elif defined(SANSA_C200V2)
-#define USB_DETECT_PIN 1
-#endif
+static int usb_status = USB_EXTRACTED;
void usb_enable(bool on)
{
@@ -51,19 +43,21 @@ void usb_enable(bool on)
#endif
}
+void usb_insert_int(void)
+{
+ usb_status = USB_INSERTED;
+}
+
+void usb_remove_int(void)
+{
+ usb_status = USB_EXTRACTED;
+}
+
void usb_init_device(void)
{
-#ifdef USB_DETECT_PIN
- GPIOA_DIR &= ~(1 << USB_DETECT_PIN); /* set as input */
-#endif
}
int usb_detect(void)
{
-#ifdef USB_DETECT_PIN
- if (GPIOA_PIN( USB_DETECT_PIN ))
- return USB_INSERTED;
- else
-#endif
- return USB_EXTRACTED;
+ return usb_status;
}
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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006 by Barry Wardelll
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef USB_TARGET_H
+#define USB_TARGET_H
+
+void usb_init_device(void);
+void usb_insert_int(void);
+void usb_remove_int(void);
+int usb_detect(void);
+
+#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)
i2c_unlock();
}
+static inline void ascodec_enable_endofch_irq(void)
+{
+ ascodec_write(AS3514_IRQ_ENRD0, IRQ_ENDOFCH);
+}
+
+static inline void ascodec_disable_endofch_irq(void)
+{
+ ascodec_write(AS3514_IRQ_ENRD0, 0);
+}
+
+static inline void ascodec_wait_adc_finished(void)
+{
+ /*
+ * FIXME: not implemented
+ *
+ * If irqs are not available on the target platform,
+ * this should be most likely implemented by polling
+ * AS3514_IRQ_ENRD2 in the same way powermgmt-ascodec.c
+ * is polling IRQ_ENDOFCH.
+ */
+}
+
extern void ascodec_suppressor_on(bool on);
#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)
/* Disable charger and minimize all settings. Reset timers, etc. */
static void disable_charger(void)
{
- ascodec_write(AS3514_IRQ_ENRD0, 0);
+ ascodec_disable_endofch_irq();
ascodec_write(AS3514_CHARGER,
TMPSUP_OFF | CHG_I_50MA | CHG_V_3_90V | CHG_OFF);
@@ -111,11 +111,11 @@ static void enable_charger(void)
ascodec_write(AS3514_CHARGER, BATT_CHG_I | BATT_CHG_V);
/* Watch for end of charge. Temperature supervision is handled in
* hardware. Charger status can be read and has no interrupt enable. */
- ascodec_write(AS3514_IRQ_ENRD0, CHG_ENDOFCH);
+ ascodec_enable_endofch_irq();
sleep(HZ/10); /* Allow charger turn-on time (it could be gradual). */
- ascodec_read(AS3514_IRQ_ENRD0); /* Clear out interrupts (important!) */
+ ascodec_disable_endofch_irq();
charge_state = CHARGING;
charger_total_timer = CHARGER_TOTAL_TIMER;
@@ -125,7 +125,7 @@ static void enable_charger(void)
void powermgmt_init_target(void)
{
/* Everything CHARGER, OFF! */
- ascodec_write(AS3514_IRQ_ENRD0, 0);
+ ascodec_disable_endofch_irq();
ascodec_write(AS3514_CHARGER,
TMPSUP_OFF | CHG_I_50MA | CHG_V_3_90V | CHG_OFF);
}