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:
parent
6550349835
commit
47ab95904e
9 changed files with 208 additions and 25 deletions
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
29
firmware/target/arm/as3525/usb-target.h
Normal file
29
firmware/target/arm/as3525/usb-target.h
Normal 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
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue