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 +++++++++++++++------ firmware/export/aic3x.h | 13 +- firmware/target/arm/tms320dm320/i2c-dm320.c | 6 + firmware/target/arm/tms320dm320/i2c-dm320.h | 12 ++ .../tms320dm320/sansa-connect/avr-sansaconnect.c | 32 +++- .../tms320dm320/sansa-connect/power-sansaconnect.c | 6 + 6 files changed, 206 insertions(+), 60 deletions(-) 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); + } +} diff --git a/firmware/export/aic3x.h b/firmware/export/aic3x.h index 17e5ea019a..4cfa0a5535 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 990dad0721..2530209402 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 be7d02ed4d..7dfc19f046 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 036b7db127..dedd017cf7 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 07c80a07c3..f73df98641 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(); } -- cgit v1.2.3