From bac6a70184b18ca17a46b3ed955944e1a4d3f032 Mon Sep 17 00:00:00 2001 From: Tomasz Moń Date: Mon, 5 Dec 2011 09:53:23 +0000 Subject: Sansa Connect: Revise codec initialization/shutdown. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31149 a1c6a512-1295-4272-9138-f99709370657 --- firmware/drivers/audio/aic3x.c | 197 ++++++++++++++++++++++++++++++----------- 1 file changed, 143 insertions(+), 54 deletions(-) (limited to 'firmware/drivers/audio/aic3x.c') diff --git a/firmware/drivers/audio/aic3x.c b/firmware/drivers/audio/aic3x.c index 5c6d5fa9ad..97eb17ebef 100644 --- a/firmware/drivers/audio/aic3x.c +++ b/firmware/drivers/audio/aic3x.c @@ -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,78 +180,88 @@ 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); - - /* Enable PLL. Set Q=16, P=1 */ - aic3x_write_reg(AIC3X_PLL_REG_A, 0x81); - /* PLL J = 53 */ - 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 */ + /* driver power-on time 200 ms, ramp-up step time 4 ms */ + aic3x_write_reg(AIC3X_POP_REDUCT, 0x7C); - /* Left DAC plays left channel, Right DAC plays right channel */ - aic3x_write_reg(AIC3X_DATAPATH, 0xA); + /* 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); - - /* GPIO1 used for audio serial data bus ADC word clock */ - aic3x_write_reg(AIC3X_GPIO1_CTRL, 0x10); + + /* 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); - - /* 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_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_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 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); - /* 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); + + /* 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, 0xB); + aic3x_write_reg(AIC3X_RIGHT_LOP_M_LVL, 0x8); + + /* Enable PLL. Set Q=16, P=1 */ + aic3x_write_reg(AIC3X_PLL_REG_A, 0x81); + /* PLL J = 53 */ + 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 R = 1 */ + aic3x_write_reg(AIC3X_OVERFLOW, 0x01); + + /* ADC fs = fs(ref)/5.5; DAC fs = fs(ref) */ + aic3x_write_reg(AIC3X_SMPL_RATE, 0x90); + + /* 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); + + /* 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); + + /* 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); - /* Power up Left, Right DAC/LOP, HPLOUT and HPROUT */ - aic3x_write_reg(AIC3X_MOD_POWER, 0xFE); + /* 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); + } +} -- cgit v1.2.3