From 47ab95904efe238568e4cc66f0d3aacd9e7a8c10 Mon Sep 17 00:00:00 2001 From: Tobias Diedrich Date: Tue, 23 Mar 2010 05:02:37 +0000 Subject: [PATCH] Add handler for audio irq. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25299 a1c6a512-1295-4272-9138-f99709370657 --- firmware/export/as3514.h | 15 +++ firmware/target/arm/adc-as3514.c | 12 +++ firmware/target/arm/as3525/ascodec-as3525.c | 108 +++++++++++++++++++- firmware/target/arm/as3525/ascodec-target.h | 8 ++ firmware/target/arm/as3525/system-as3525.c | 1 + firmware/target/arm/as3525/usb-as3525.c | 30 +++--- firmware/target/arm/as3525/usb-target.h | 29 ++++++ firmware/target/arm/ascodec-target.h | 22 ++++ firmware/target/arm/powermgmt-ascodec.c | 8 +- 9 files changed, 208 insertions(+), 25 deletions(-) create mode 100644 firmware/target/arm/as3525/usb-target.h 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); }