summaryrefslogtreecommitdiff
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
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
-rw-r--r--firmware/drivers/audio/aic3x.c197
-rw-r--r--firmware/export/aic3x.h13
-rw-r--r--firmware/target/arm/tms320dm320/i2c-dm320.c6
-rw-r--r--firmware/target/arm/tms320dm320/i2c-dm320.h12
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c32
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c6
6 files changed, 206 insertions, 60 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);
+ }
+}
diff --git a/firmware/export/aic3x.h b/firmware/export/aic3x.h
index 17e5ea0..4cfa0a5 100644
--- a/firmware/export/aic3x.h
+++ b/firmware/export/aic3x.h
@@ -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
diff --git a/firmware/target/arm/tms320dm320/i2c-dm320.c b/firmware/target/arm/tms320dm320/i2c-dm320.c
index 990dad0..2530209 100644
--- a/firmware/target/arm/tms320dm320/i2c-dm320.c
+++ b/firmware/target/arm/tms320dm320/i2c-dm320.c
@@ -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
diff --git a/firmware/target/arm/tms320dm320/i2c-dm320.h b/firmware/target/arm/tms320dm320/i2c-dm320.h
index be7d02e..7dfc19f 100644
--- a/firmware/target/arm/tms320dm320/i2c-dm320.h
+++ b/firmware/target/arm/tms320dm320/i2c-dm320.h
@@ -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
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
index 036b7db..dedd017 100644
--- a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
+++ b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
@@ -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
}
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c
index 07c80a0..f73df98 100644
--- a/firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c
+++ b/firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c
@@ -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();
}