Add handler for audio irq.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25299 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Tobias Diedrich 2010-03-23 05:02:37 +00:00
parent 6550349835
commit 47ab95904e
9 changed files with 208 additions and 25 deletions

View file

@ -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 */

View file

@ -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)
{

View file

@ -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

View file

@ -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 */

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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 */

View file

@ -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);
}