summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
authorTomasz Moń <desowin@gmail.com>2011-12-05 09:53:23 +0000
committerTomasz Moń <desowin@gmail.com>2011-12-05 09:53:23 +0000
commitbac6a70184b18ca17a46b3ed955944e1a4d3f032 (patch)
treeb037d8e36e7d76c32d34de9c72f20dab3ec816ec /firmware/drivers
parent4811b516a35ab6d391cc738c17b9aa8a26505fbe (diff)
downloadrockbox-bac6a70184b18ca17a46b3ed955944e1a4d3f032.zip
rockbox-bac6a70184b18ca17a46b3ed955944e1a4d3f032.tar.gz
rockbox-bac6a70184b18ca17a46b3ed955944e1a4d3f032.tar.bz2
rockbox-bac6a70184b18ca17a46b3ed955944e1a4d3f032.tar.xz
Sansa Connect: Revise codec initialization/shutdown.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31149 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/drivers')
-rw-r--r--firmware/drivers/audio/aic3x.c197
1 files changed, 143 insertions, 54 deletions
diff --git a/firmware/drivers/audio/aic3x.c b/firmware/drivers/audio/aic3x.c
index 5c6d5fa..97eb17e 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);
+ }
+}