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:
Tomasz Moń 2011-12-05 09:53:23 +00:00
parent 4811b516a3
commit bac6a70184
6 changed files with 219 additions and 73 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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