Sansa Connect: Revise codec initialization/shutdown.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31149 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
4811b516a3
commit
bac6a70184
6 changed files with 219 additions and 73 deletions
|
@ -23,11 +23,6 @@
|
|||
#include "system.h"
|
||||
#include "string.h"
|
||||
#include "audio.h"
|
||||
|
||||
#ifdef SANSA_CONNECT
|
||||
#include "avr-sansaconnect.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_I2C == I2C_DM320
|
||||
#include "i2c-dm320.h"
|
||||
#endif
|
||||
|
@ -84,11 +79,41 @@ static void aic3x_write_reg(unsigned reg, unsigned value)
|
|||
}
|
||||
}
|
||||
|
||||
static unsigned char aic3x_read_reg(unsigned reg)
|
||||
{
|
||||
unsigned char data;
|
||||
|
||||
#if CONFIG_I2C == I2C_DM320
|
||||
if (i2c_read_bytes(AIC3X_ADDR, reg, &data, 1))
|
||||
#else
|
||||
#warning Implement aic3x_read_reg()
|
||||
#endif
|
||||
{
|
||||
logf("AIC3X read error reg=0x%0x", reg);
|
||||
data = 0;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void aic3x_change_reg(unsigned reg, unsigned char or_mask,
|
||||
unsigned char and_mask)
|
||||
{
|
||||
unsigned char data;
|
||||
|
||||
data = aic3x_read_reg(reg);
|
||||
|
||||
data &= and_mask;
|
||||
data |= or_mask;
|
||||
|
||||
aic3x_write_reg(reg, data);
|
||||
}
|
||||
|
||||
static void aic3x_apply_volume(void)
|
||||
{
|
||||
unsigned char data[3];
|
||||
|
||||
#if 0 /* handle page switching onve we use first page at all */
|
||||
#if 0 /* handle page switching once we use first page at all */
|
||||
aic3x_write_reg(0, 0); /* switch to page 0 */
|
||||
#endif
|
||||
|
||||
|
@ -113,11 +138,29 @@ static void audiohw_mute(bool mute)
|
|||
{
|
||||
if (mute)
|
||||
{
|
||||
/* DAC_L1 routed to HPLOUT, mute */
|
||||
aic3x_write_reg(AIC3X_DAC_L1_VOL, 0xF6);
|
||||
/* DAC_R1 routed to HPROUT, mute */
|
||||
aic3x_write_reg(AIC3X_DAC_R1_VOL, 0xF6);
|
||||
/* DAC_L1 routed to MONO_LOP/M, mute */
|
||||
aic3x_write_reg(AIC3X_DAC_L1_MONO_LOP_M_VOL, 0xF6);
|
||||
/* DAC_R1 routed to MONO_LOP/M, mute */
|
||||
aic3x_write_reg(AIC3X_DAC_R1_MONO_LOP_M_VOL, 0xF6);
|
||||
|
||||
volume_left |= 0x80;
|
||||
volume_right |= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* DAC_L1 routed to HPLOUT, volume analog gain 0xC (-6.0dB) */
|
||||
aic3x_write_reg(AIC3X_DAC_L1_VOL, 0x8C);
|
||||
/* DAC_R1 routed to HPROUT, volume analog gain 0xC (-6.0 dB) */
|
||||
aic3x_write_reg(AIC3X_DAC_R1_VOL, 0x8C);
|
||||
/* DAC_L1 routed to MONO_LOP/M, gain 0x2 (-1.0dB) */
|
||||
aic3x_write_reg(AIC3X_DAC_L1_MONO_LOP_M_VOL, 0x92);
|
||||
/* DAC_R1 routed to MONO_LOP/M, gain 0x2 (-1.0dB) */
|
||||
aic3x_write_reg(AIC3X_DAC_R1_MONO_LOP_M_VOL, 0x92);
|
||||
|
||||
volume_left &= 0x7F;
|
||||
volume_right &= 0x7F;
|
||||
}
|
||||
|
@ -137,8 +180,51 @@ void audiohw_init(void)
|
|||
/* Do software reset (self-clearing) */
|
||||
aic3x_write_reg(AIC3X_SOFT_RESET, 0x80);
|
||||
|
||||
/* ADC fs = fs(ref)/5.5; DAC fs = fs(ref) */
|
||||
aic3x_write_reg(AIC3X_SMPL_RATE, 0x90);
|
||||
/* driver power-on time 200 ms, ramp-up step time 4 ms */
|
||||
aic3x_write_reg(AIC3X_POP_REDUCT, 0x7C);
|
||||
|
||||
/* Output common-move voltage 1.35V, disable LINE2[LR] bypass */
|
||||
/* Output soft-stepping = one step per fs */
|
||||
aic3x_write_reg(AIC3X_POWER_OUT, 0x00);
|
||||
|
||||
/* Audio data interface */
|
||||
/* GPIO1 used for audio serial data bus ADC word clock */
|
||||
aic3x_write_reg(AIC3X_GPIO1_CTRL, 0x10);
|
||||
/* BCLK and WCLK are outputs (master mode) */
|
||||
aic3x_write_reg(AIC3X_DATA_REG_A, 0xC0);
|
||||
/* right-justified mode */
|
||||
aic3x_write_reg(AIC3X_DATA_REG_B, 0x80);
|
||||
/* data offset = 0 clocks */
|
||||
aic3x_write_reg(AIC3X_DATA_REG_C, 0);
|
||||
|
||||
/* Left DAC plays left channel, Right DAC plays right channel */
|
||||
aic3x_write_reg(AIC3X_DATAPATH, 0xA);
|
||||
|
||||
/* power left and right DAC, HPLCOM constant VCM output */
|
||||
aic3x_write_reg(AIC3X_DAC_POWER, 0xD0);
|
||||
/* HPRCOM as constant VCM output. Enable short-circuit protection
|
||||
(limit current) */
|
||||
aic3x_write_reg(AIC3X_HIGH_POWER, 0xC);
|
||||
|
||||
/* DAC_L1 routed to HPLOUT */
|
||||
aic3x_write_reg(AIC3X_DAC_L1_VOL, 0x80);
|
||||
/* DAC_R1 routed to HPROUT */
|
||||
aic3x_write_reg(AIC3X_DAC_R1_VOL, 0x80);
|
||||
|
||||
/* DAC_L1 routed to MONO_LOP/M */
|
||||
aic3x_write_reg(AIC3X_DAC_L1_MONO_LOP_M_VOL, 0x80);
|
||||
/* DAC_R1 routed to MONO_LOP/M */
|
||||
aic3x_write_reg(AIC3X_DAC_R1_MONO_LOP_M_VOL, 0x80);
|
||||
|
||||
/* DAC_L1 routed to LEFT_LOP/M */
|
||||
aic3x_write_reg(AIC3X_DAC_L1_LEFT_LOP_M_VOL, 0x80);
|
||||
/* DAC_R1 routed to RIGHT_LOP/M */
|
||||
aic3x_write_reg(AIC3X_DAC_R1_RIGHT_LOP_M_VOL, 0x80);
|
||||
|
||||
/* LEFT_LOP/M output level 0dB, not muted */
|
||||
aic3x_write_reg(AIC3X_LEFT_LOP_M_LVL, 0x8);
|
||||
/* RIGHT_LOP/M output level 0dB, not muted */
|
||||
aic3x_write_reg(AIC3X_RIGHT_LOP_M_LVL, 0x8);
|
||||
|
||||
/* Enable PLL. Set Q=16, P=1 */
|
||||
aic3x_write_reg(AIC3X_PLL_REG_A, 0x81);
|
||||
|
@ -146,69 +232,36 @@ void audiohw_init(void)
|
|||
aic3x_write_reg(AIC3X_PLL_REG_B, 0xD4);
|
||||
/* PLL D = 5211 */
|
||||
aic3x_write_reg(AIC3X_PLL_REG_C, 0x51);
|
||||
aic3x_write_reg(AIC3X_PLL_REG_D, 0x6C); /* PLL D = 5211 */
|
||||
aic3x_write_reg(AIC3X_PLL_REG_D, 0x6C);
|
||||
/* PLL R = 1 */
|
||||
aic3x_write_reg(AIC3X_OVERFLOW, 0x01);
|
||||
|
||||
/* Left DAC plays left channel, Right DAC plays right channel */
|
||||
aic3x_write_reg(AIC3X_DATAPATH, 0xA);
|
||||
/* ADC fs = fs(ref)/5.5; DAC fs = fs(ref) */
|
||||
aic3x_write_reg(AIC3X_SMPL_RATE, 0x90);
|
||||
|
||||
/* Audio data interface */
|
||||
/* BCLK and WCLK are outputs (master mode) */
|
||||
aic3x_write_reg(AIC3X_DATA_REG_A, 0xC0);
|
||||
/* right-justified mode */
|
||||
aic3x_write_reg(AIC3X_DATA_REG_B, 0x80);
|
||||
/* data offset = 0 clocks */
|
||||
aic3x_write_reg(AIC3X_DATA_REG_C, 0);
|
||||
|
||||
/* GPIO1 used for audio serial data bus ADC word clock */
|
||||
aic3x_write_reg(AIC3X_GPIO1_CTRL, 0x10);
|
||||
/* HPLOUT output level 0dB, muted, high impedance */
|
||||
aic3x_write_reg(AIC3X_HPLOUT_LVL, 0x04);
|
||||
/* HPROUT output level 0dB, muted, high impedance */
|
||||
aic3x_write_reg(AIC3X_HPROUT_LVL, 0x04);
|
||||
|
||||
/* power left and right DAC, HPLCOM constant VCM output */
|
||||
aic3x_write_reg(AIC3X_DAC_POWER, 0xD0);
|
||||
/* HPRCOM as constant VCM output. Enable short-circuit protection
|
||||
(limit current) */
|
||||
aic3x_write_reg(AIC3X_HIGH_POWER, 0xC);
|
||||
|
||||
/* driver power-on time 200 ms, ramp-up step time 4 ms */
|
||||
aic3x_write_reg(AIC3X_POP_REDUCT, 0x7C);
|
||||
|
||||
/* DAC_L1 routed to HPLOUT, volume analog gain 0xC (-6.0dB) */
|
||||
aic3x_write_reg(AIC3X_DAC_L1_VOL, 0x8C);
|
||||
/* HPLOUT output level 0dB, not muted, fully powered up */
|
||||
aic3x_write_reg(AIC3X_HPLOUT_LVL, 0xB);
|
||||
|
||||
/* HPLCOM is muted */
|
||||
aic3x_write_reg(AIC3X_HPLCOM_LVL, 0x7);
|
||||
|
||||
/* DAC_R1 routed to HPROUT, volume analog gain 0xC (-6.0 dB) */
|
||||
aic3x_write_reg(AIC3X_DAC_R1_VOL, 0x8C);
|
||||
/* HPROUT output level 0dB, not muted, fully powered up */
|
||||
aic3x_write_reg(AIC3X_HPROUT_LVL, 0xB);
|
||||
|
||||
/* DAC_L1 routed to MONO_LOP/M, gain 0x2 (-1.0dB) */
|
||||
aic3x_write_reg(AIC3X_DAC_L1_MONO_LOP_M_VOL, 0x92);
|
||||
/* DAC_R1 routed to MONO_LOP/M, gain 0x2 (-1.0dB) */
|
||||
aic3x_write_reg(AIC3X_DAC_R1_MONO_LOP_M_VOL, 0x92);
|
||||
|
||||
/* MONO_LOP output level 6dB, not muted, fully powered up */
|
||||
aic3x_write_reg(AIC3X_MONO_LOP_M_LVL, 0x6b);
|
||||
|
||||
/* DAC_L1 routed to LEFT_LOP/M */
|
||||
aic3x_write_reg(AIC3X_DAC_L1_LEFT_LOP_M_VOL, 0x80);
|
||||
/* LEFT_LOP/M output level 0dB, not muted */
|
||||
aic3x_write_reg(AIC3X_LEFT_LOP_M_LVL, 0xB);
|
||||
|
||||
/* DAC_R1 routed to RIGHT_LOP/M */
|
||||
aic3x_write_reg(AIC3X_DAC_R1_RIGHT_LOP_M_VOL, 0x80);
|
||||
/* RIGHT_LOP/M output level 0dB, not muted */
|
||||
aic3x_write_reg(AIC3X_RIGHT_LOP_M_LVL, 0xB);
|
||||
/* HPLCOM is high impedance when powered down, not fully powered up */
|
||||
aic3x_write_reg(AIC3X_HPLCOM_LVL, 0x04);
|
||||
}
|
||||
|
||||
void audiohw_postinit(void)
|
||||
{
|
||||
audiohw_mute(false);
|
||||
audiohw_mute(false);
|
||||
|
||||
/* Power up Left, Right DAC/LOP, HPLOUT and HPROUT */
|
||||
aic3x_write_reg(AIC3X_MOD_POWER, 0xFE);
|
||||
/* HPLOUT output level 0dB, not muted, fully powered up */
|
||||
aic3x_write_reg(AIC3X_HPLOUT_LVL, 0x09);
|
||||
/* HPROUT output level 0dB, not muted, fully powered up */
|
||||
aic3x_write_reg(AIC3X_HPROUT_LVL, 0x09);
|
||||
|
||||
/* MONO_LOP output level 6dB, not muted */
|
||||
aic3x_write_reg(AIC3X_MONO_LOP_M_LVL, 0x69);
|
||||
|
||||
/* PGA_R is not routed to MONO_LOP/M, analog gain -52.7dB */
|
||||
aic3x_write_reg(AIC3X_PGA_R_MONO_LOP_M_VOL, 0x69);
|
||||
}
|
||||
|
||||
void audiohw_set_frequency(int fsel)
|
||||
|
@ -238,10 +291,46 @@ void audiohw_set_headphone_vol(int vol_l, int vol_r)
|
|||
/* Nice shutdown of AIC3X codec */
|
||||
void audiohw_close(void)
|
||||
{
|
||||
audiohw_mute(true);
|
||||
#ifdef SANSA_CONNECT
|
||||
avr_hid_reset_codec();
|
||||
#endif
|
||||
/* HPLOUT, HPROUT, HPLCOM not fully powered up */
|
||||
aic3x_change_reg(AIC3X_HPLOUT_LVL, 0x00, 0xFE);
|
||||
aic3x_change_reg(AIC3X_HPROUT_LVL, 0x00, 0xFE);
|
||||
aic3x_change_reg(AIC3X_HPLCOM_LVL, 0x00, 0xFC);
|
||||
|
||||
/* MONO_LOP/M, LEFT_LOP/M, RIGHT_LOP/M muted, not fully powered up */
|
||||
aic3x_change_reg(AIC3X_MONO_LOP_M_LVL, 0x00, 0xF6);
|
||||
aic3x_change_reg(AIC3X_LEFT_LOP_M_LVL, 0x00, 0xF6);
|
||||
aic3x_change_reg(AIC3X_RIGHT_LOP_M_LVL, 0x00, 0xF6);
|
||||
|
||||
/* Power down left and right DAC */
|
||||
aic3x_change_reg(AIC3X_DAC_POWER, 0x00, 0x30);
|
||||
|
||||
/* Disable PLL */
|
||||
aic3x_change_reg(AIC3X_PLL_REG_A, 0x00, 0x7F);
|
||||
}
|
||||
|
||||
void aic3x_switch_output(bool stereo)
|
||||
{
|
||||
if (stereo)
|
||||
{
|
||||
/* mute MONO_LOP/M */
|
||||
aic3x_change_reg(AIC3X_MONO_LOP_M_LVL, 0x00, 0xF6);
|
||||
/* HPLOUT fully powered up */
|
||||
aic3x_change_reg(AIC3X_HPLOUT_LVL, 0x01, 0xFF);
|
||||
/* HPROUT fully powered up */
|
||||
aic3x_change_reg(AIC3X_HPROUT_LVL, 0x01, 0xFF);
|
||||
/* HPLCOM fully powered up */
|
||||
aic3x_change_reg(AIC3X_HPLCOM_LVL, 0x01, 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* MONO_LOP/M not muted */
|
||||
aic3x_change_reg(AIC3X_MONO_LOP_M_LVL, 0x09, 0xFF);
|
||||
/* HPLOUT not fully powered up */
|
||||
aic3x_change_reg(AIC3X_HPLOUT_LVL, 0x00, 0xFE);
|
||||
/* HPROUT not fully powered up */
|
||||
aic3x_change_reg(AIC3X_HPROUT_LVL, 0x00, 0xFE);
|
||||
/* HPLCOM not fully powered up */
|
||||
aic3x_change_reg(AIC3X_HPLCOM_LVL, 0x00, 0xFE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ extern int tenthdb2master(int db);
|
|||
/*** definitions ***/
|
||||
extern void audiohw_set_headphone_vol(int vol_l, int vol_r);
|
||||
|
||||
extern void aic3x_switch_output(bool stereo);
|
||||
|
||||
/* Page 0 registers */
|
||||
#define AIC3X_PAGE_SELECT 0
|
||||
#define AIC3X_SOFT_RESET 1
|
||||
|
@ -42,10 +44,17 @@ extern void audiohw_set_headphone_vol(int vol_l, int vol_r);
|
|||
#define AIC3X_DATA_REG_A 8
|
||||
#define AIC3X_DATA_REG_B 9
|
||||
#define AIC3X_DATA_REG_C 10
|
||||
#define AIC3X_OVERFLOW 11
|
||||
|
||||
#define AIC3X_LINE1L_LEFTADC 19
|
||||
|
||||
#define AIC3X_LINE1R_RIGHTADC 22
|
||||
|
||||
#define AIC3X_DAC_POWER 37
|
||||
#define AIC3X_HIGH_POWER 38
|
||||
|
||||
#define AIC3X_POWER_OUT 40
|
||||
|
||||
#define AIC3X_POP_REDUCT 42
|
||||
#define AIC3X_LEFT_VOL 43
|
||||
#define AIC3X_RIGHT_VOL 44
|
||||
|
@ -60,7 +69,9 @@ extern void audiohw_set_headphone_vol(int vol_l, int vol_r);
|
|||
|
||||
#define AIC3X_DAC_L1_MONO_LOP_M_VOL 75
|
||||
|
||||
#define AIC3X_DAC_R1_MONO_LOP_M_VOL 76
|
||||
#define AIC3X_LINE2R_MONO_LOP_M_VOL 76
|
||||
#define AIC3X_PGA_R_MONO_LOP_M_VOL 77
|
||||
#define AIC3X_DAC_R1_MONO_LOP_M_VOL 78
|
||||
|
||||
#define AIC3X_MONO_LOP_M_LVL 79
|
||||
|
||||
|
|
|
@ -287,4 +287,10 @@ int i2c_read(unsigned short address, unsigned char* buf, int count)
|
|||
return i2c_read_data(dm320_i2c_bus, address, -1, buf, count);
|
||||
}
|
||||
|
||||
int i2c_read_bytes(unsigned short address, unsigned short reg,
|
||||
unsigned char* buf, int count)
|
||||
{
|
||||
return i2c_read_data(dm320_i2c_bus, address, reg, buf, count);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,6 +19,18 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef I2C_DM320_H
|
||||
#define I2C_DM320_H
|
||||
|
||||
#include "system.h"
|
||||
|
||||
void i2c_init(void);
|
||||
int i2c_write(unsigned short address, const unsigned char *data, int count);
|
||||
int i2c_read(unsigned short address, unsigned char* buf, int count);
|
||||
|
||||
#ifdef HAVE_SOFTWARE_I2C
|
||||
int i2c_read_bytes(unsigned short address, unsigned short reg,
|
||||
unsigned char* buf, int count);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "button.h"
|
||||
#include "backlight.h"
|
||||
#include "powermgmt.h"
|
||||
#include "aic3x.h"
|
||||
|
||||
//#define BUTTON_DEBUG
|
||||
|
||||
|
@ -405,6 +406,26 @@ void GIO0(void)
|
|||
/* interrupt will be enabled back after button read */
|
||||
queue_post(&btn_queue, BTN_INTERRUPT, 0);
|
||||
}
|
||||
|
||||
void GIO2(void) __attribute__ ((section(".icode")));
|
||||
void GIO2(void)
|
||||
{
|
||||
/* Clear interrupt */
|
||||
IO_INTC_IRQ1 = (1 << 7);
|
||||
/* Disable interrupt */
|
||||
IO_INTC_EINT1 &= ~INTR_EINT1_EXT2;
|
||||
|
||||
if (IO_GIO_BITSET0 & 0x04)
|
||||
{
|
||||
aic3x_switch_output(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
aic3x_switch_output(true);
|
||||
}
|
||||
|
||||
IO_INTC_EINT1 |= INTR_EINT1_EXT2;
|
||||
}
|
||||
#endif
|
||||
|
||||
void button_init_device(void)
|
||||
|
@ -425,12 +446,13 @@ void button_init_device(void)
|
|||
avr_hid_get_state();
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
IO_GIO_IRQPORT |= 0x01; /* Enable GIO0 external interrupt */
|
||||
IO_GIO_INV0 &= ~0x01; /* Clear INV for GIO0 (falling edge detection) */
|
||||
IO_GIO_IRQEDGE &= ~0x01; /* Set edge detection (falling) */
|
||||
IO_GIO_IRQPORT |= 0x05; /* Enable GIO0/GIO2 external interrupt */
|
||||
IO_GIO_INV0 &= ~0x05; /* Clear INV for GIO0/GIO2 */
|
||||
/* falling edge detection on GIO0, any edge on GIO2 */
|
||||
IO_GIO_IRQEDGE = (IO_GIO_IRQEDGE & ~0x01) | 0x04;
|
||||
|
||||
/* Enable GIO0 interrupt */
|
||||
IO_INTC_EINT1 |= INTR_EINT1_EXT0;
|
||||
/* Enable GIO0 and GIO2 interrupts */
|
||||
IO_INTC_EINT1 |= INTR_EINT1_EXT0 | INTR_EINT1_EXT2;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,9 @@ static void tps65021_write_reg(unsigned reg, unsigned value)
|
|||
|
||||
void power_init(void)
|
||||
{
|
||||
/* Enable LDO */
|
||||
tps65021_write_reg(0x03, 0xFD);
|
||||
|
||||
/* PWM mode */
|
||||
tps65021_write_reg(0x04, 0xB2);
|
||||
|
||||
|
@ -61,6 +64,9 @@ void power_init(void)
|
|||
|
||||
void power_off(void)
|
||||
{
|
||||
/* Disable GIO0 and GIO2 interrupts */
|
||||
IO_INTC_EINT1 &= ~(INTR_EINT1_EXT2 | INTR_EINT1_EXT0);
|
||||
|
||||
avr_hid_reset_codec();
|
||||
avr_hid_power_off();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue