From ed4d7a33bdeba5ce11512ee617398a2840797203 Mon Sep 17 00:00:00 2001 From: Linus Nielsen Feltzing Date: Fri, 21 Jul 2006 08:42:28 +0000 Subject: Patch #5347 by Rani Hod - Adds FM radio and recording features to the iAudio X5. Also includes a rewrite of the Coldfire I2C driver to include both read and write. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10272 a1c6a512-1295-4272-9138-f99709370657 --- apps/main.c | 4 +- apps/recorder/radio.c | 57 ++++++- apps/recorder/recording.c | 16 ++ firmware/drivers/fmradio_i2c.c | 17 ++ firmware/drivers/i2c-coldfire.c | 229 ++++++++++++++++---------- firmware/drivers/tlv320.c | 119 ++++++++----- firmware/drivers/uda1380.c | 26 ++- firmware/export/config-iaudiox5.h | 7 +- firmware/export/fmradio_i2c.h | 4 +- firmware/export/i2c-coldfire.h | 10 +- firmware/export/sound.h | 2 +- firmware/export/tlv320.h | 3 +- firmware/pcm_record.c | 83 ++++++++-- firmware/sound.c | 25 ++- firmware/target/coldfire/iaudio/x5/power-x5.c | 14 ++ 15 files changed, 449 insertions(+), 167 deletions(-) diff --git a/apps/main.c b/apps/main.c index 4f31cdb58a..8ee6adfe4f 100644 --- a/apps/main.c +++ b/apps/main.c @@ -72,7 +72,7 @@ #else #define pcmbuf_init() #endif -#if (defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES)) && !defined(SIMULATOR) +#if (CONFIG_CODEC == SWCODEC) && defined(HAVE_RECORDING) && !defined(SIMULATOR) #include "pcm_record.h" #define SETTINGS_RESET BUTTON_REC #endif @@ -425,7 +425,7 @@ void init(void) talk_init(); audio_init(); -#if (defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES)) && !defined(SIMULATOR) +#if (CONFIG_CODEC == SWCODEC) && defined(HAVE_RECORDING) && !defined(SIMULATOR) pcm_rec_init(); #endif diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c index 291079b4b0..a29620b46c 100644 --- a/apps/recorder/radio.c +++ b/apps/recorder/radio.c @@ -64,7 +64,13 @@ #ifdef CONFIG_TUNER #if CONFIG_CODEC == SWCODEC +#ifdef HAVE_UDA1380 #include "uda1380.h" +#endif +#ifdef HAVE_TLV320 +#include "tlv320.h" +#endif + #include "pcm_record.h" #endif @@ -109,6 +115,35 @@ #define FM_STOP BUTTON_OFF #define FM_RC_STOP BUTTON_RC_STOP +#elif (CONFIG_KEYPAD == IAUDIO_X5_PAD) +/* pause/play - short PLAY */ +#define FM_PLAY_PRE BUTTON_PLAY +#define FM_RC_PLAY_PRE BUTTON_RC_PLAY +#define FM_PLAY (BUTTON_PLAY | BUTTON_REL) +#define FM_RC_PLAY (BUTTON_RC_PLAY | BUTTON_REL) +/* preset/scan mode - long PLAY */ +#define FM_MODE (BUTTON_PLAY | BUTTON_REPEAT) +#define FM_RC_MODE (BUTTON_RC_PLAY | BUTTON_REPEAT) +/* preset menu - short SELECT */ +#define FM_PRESET_PRE BUTTON_SELECT +#define FM_RC_PRESET_PRE BUTTON_RC_MENU +#define FM_PRESET (BUTTON_SELECT | BUTTON_REL) +#define FM_RC_PRESET (BUTTON_RC_MENU | BUTTON_REL) +/* fm menu - long SELECT */ +#define FM_MENU (BUTTON_SELECT | BUTTON_REPEAT) +#define FM_RC_MENU (BUTTON_RC_MENU | BUTTON_REPEAT) +/* main menu(exit radio while playing) - REC */ +#define FM_EXIT_PRE BUTTON_REC +#define FM_EXIT (BUTTON_REC | BUTTON_REL) +#define FM_RC_EXIT_PRE BUTTON_RC_MODE +#define FM_RC_EXIT (BUTTON_RC_MODE | BUTTON_REL) +/* prev/next preset on the remote - REW/FF */ +#define FM_NEXT_PRESET (BUTTON_RC_FF | BUTTON_REL) +#define FM_PREV_PRESET (BUTTON_RC_REW | BUTTON_REL) +/* stop and exit radio - ON */ +#define FM_STOP BUTTON_POWER +#define FM_RC_STOP (BUTTON_RC_MODE | BUTTON_REPEAT) + #elif CONFIG_KEYPAD == ONDIO_PAD /* restricted keypad */ #define FM_MENU (BUTTON_MENU | BUTTON_REPEAT) #define FM_RECORD_DBLPRE BUTTON_MENU @@ -158,7 +193,7 @@ int radio_get(int setting); #if CONFIG_TUNER == S1A0903X01 /* FM recorder */ #define radio_set samsung_set #define radio_get samsung_get -#elif CONFIG_TUNER == TEA5767 /* Iriver */ +#elif CONFIG_TUNER == TEA5767 /* iriver, iaudio */ #define radio_set philips_set #define radio_get philips_get #elif CONFIG_TUNER == (S1A0903X01 | TEA5767) /* OndioFM */ @@ -387,8 +422,15 @@ bool radio_screen(void) #else peak_meter_enabled = false; + +#ifdef HAVE_UDA1380 uda1380_enable_recording(false); uda1380_set_monitor(true); +#elif defined(HAVE_TLV320) + //tlv320_enable_recording(false); + tlv320_set_recvol(23, 23, AUDIO_GAIN_LINEIN); /* 0dB */ + tlv320_set_monitor(true); +#endif /* Set the input multiplexer to FM */ pcm_rec_mux(1); @@ -971,7 +1013,7 @@ bool radio_screen(void) while(1) { button = button_get(true); - if(button == (BUTTON_OFF | BUTTON_REL)) + if(button == (FM_STOP | BUTTON_REL)) break; } } @@ -1004,6 +1046,11 @@ bool radio_screen(void) radio_stop(); #ifndef SIMULATOR /* SIMULATOR. Catch FMRADIO_OFF status for the sim. */ #if CONFIG_CODEC == SWCODEC +#ifdef HAVE_TLV320 + //tlv320_disable_recording(); + tlv320_set_monitor(false); +#endif + pcm_rec_mux(0); /* Line In */ peak_meter_enabled = true; #endif @@ -1320,7 +1367,7 @@ int handle_radio_presets_cb(int key, int m) key = BUTTON_NONE; break; #endif -#if (CONFIG_KEYPAD != IRIVER_H100_PAD) && (CONFIG_KEYPAD != IRIVER_H300_PAD) +#if (CONFIG_KEYPAD != IRIVER_H100_PAD) && (CONFIG_KEYPAD != IRIVER_H300_PAD) && (CONFIG_KEYPAD != IAUDIO_X5_PAD) #ifdef FM_PRESET case FM_PRESET: menu_draw(m); @@ -1565,7 +1612,7 @@ int radio_menu_cb(int key, int m) (void)m; switch(key) { -#if (CONFIG_KEYPAD != IRIVER_H100_PAD) && (CONFIG_KEYPAD != IRIVER_H300_PAD) +#if (CONFIG_KEYPAD != IRIVER_H100_PAD) && (CONFIG_KEYPAD != IRIVER_H300_PAD) && (CONFIG_KEYPAD != IAUDIO_X5_PAD) #ifdef MENU_ENTER2 case MENU_ENTER2: #endif @@ -1574,7 +1621,7 @@ int radio_menu_cb(int key, int m) key = BUTTON_NONE; /* eat the downpress, next menu reacts on release */ break; -#if (CONFIG_KEYPAD != IRIVER_H100_PAD) && (CONFIG_KEYPAD != IRIVER_H300_PAD) +#if (CONFIG_KEYPAD != IRIVER_H100_PAD) && (CONFIG_KEYPAD != IRIVER_H300_PAD) && (CONFIG_KEYPAD != IAUDIO_X5_PAD) #ifdef MENU_ENTER2 case MENU_ENTER2 | BUTTON_REL: #endif diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c index 09ec0f43f5..d4094a2511 100644 --- a/apps/recorder/recording.c +++ b/apps/recorder/recording.c @@ -34,6 +34,9 @@ #ifdef HAVE_UDA1380 #include "uda1380.h" #endif +#ifdef HAVE_TLV320 +#include "tlv320.h" +#endif #include "mp3_playback.h" #include "mas.h" @@ -109,6 +112,16 @@ #define REC_RC_PREV BUTTON_RC_REW #define REC_RC_SETTINGS BUTTON_RC_MODE +#elif (CONFIG_KEYPAD == IAUDIO_X5_PAD) +#define REC_SHUTDOWN (BUTTON_POWER | BUTTON_REPEAT) +#define REC_STOPEXIT BUTTON_POWER +#define REC_RECPAUSE BUTTON_REC +#define REC_INC BUTTON_RIGHT +#define REC_DEC BUTTON_LEFT +#define REC_NEXT BUTTON_DOWN +#define REC_PREV BUTTON_UP +#define REC_SETTINGS BUTTON_PLAY + #elif CONFIG_KEYPAD == GMINI100_PAD #define REC_SHUTDOWN (BUTTON_OFF | BUTTON_REPEAT) #define REC_STOPEXIT BUTTON_OFF @@ -362,6 +375,9 @@ bool recording_screen(void) audio_stop(); /* Set peak meter to recording mode */ peak_meter_playback(false); +#ifdef IAUDIO_X5 + pcm_rec_mux(0); /* select line-in (not radio) */ +#endif #if defined(HAVE_SPDIF_IN) && !defined(SIMULATOR) if (global_settings.rec_source == SOURCE_SPDIF) diff --git a/firmware/drivers/fmradio_i2c.c b/firmware/drivers/fmradio_i2c.c index 2475084696..6f87e15b3e 100644 --- a/firmware/drivers/fmradio_i2c.c +++ b/firmware/drivers/fmradio_i2c.c @@ -27,6 +27,22 @@ #if (CONFIG_TUNER & TEA5767) #if (CONFIG_I2C == I2C_COLDFIRE) + +#ifdef IAUDIO_X5 +#include "i2c-coldfire.h" + +int fmradio_i2c_write(unsigned char address, const unsigned char* buf, + int count) +{ + return i2c_write(I2C_IFACE_0, address, buf, count); +} + +int fmradio_i2c_read(unsigned char address, unsigned char* buf, int count) +{ + return i2c_read(I2C_IFACE_0, address, buf, count); +} +#else + /* cute little functions, atomic read-modify-write */ /* SDA is GPIO1,23 */ @@ -242,6 +258,7 @@ int fmradio_i2c_read(int address, unsigned char* buf, int count) fmradio_i2c_stop(); return x; } +#endif /* ! IAUDIO_X5 */ #else /* cute little functions, atomic read-modify-write */ /* SDA is PB4 */ diff --git a/firmware/drivers/i2c-coldfire.c b/firmware/drivers/i2c-coldfire.c index 47aeba757f..a628ce5f0e 100644 --- a/firmware/drivers/i2c-coldfire.c +++ b/firmware/drivers/i2c-coldfire.c @@ -5,6 +5,7 @@ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ + * * $Id$ * * Copyright (C) 2005 by Andy Young @@ -23,17 +24,16 @@ #include "system.h" #include "i2c-coldfire.h" -#define I2C_DEVICE_1 ((volatile unsigned char *)&MADR) -#define I2C_DEVICE_2 ((volatile unsigned char *)&MADR2) -/* Local functions definitions */ +/* --- Local functions - declarations --- */ + +static int i2c_start(volatile unsigned char *iface); +static int i2c_wait_for_slave(volatile unsigned char *iface); +static int i2c_outb(volatile unsigned char *iface, unsigned char byte); +inline void i2c_stop(volatile unsigned char *iface); -static int i2c_write_byte(int device, unsigned char data); -static int i2c_gen_start(int device); -static void i2c_gen_stop(int device); -static volatile unsigned char *i2c_get_addr(int device); -/* Public functions */ +/* --- Public functions - implementation --- */ void i2c_init(void) { @@ -55,14 +55,15 @@ void i2c_init(void) #endif /* I2C Clock divisor = 160 => 124.1556 MHz / 2 / 160 = 388.08 kHz */ - MFDR = 0x0d; + MFDR = 0x0d; MFDR2 = 0x0d; #ifdef IAUDIO_X5 - MBCR = IEN; /* Enable interface */ + MBCR = IEN; /* Enable interface */ + MBCR2 = IEN; #endif -#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) +#if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES) /* Audio Codec */ MBDR = 0; /* iRiver firmware does this */ MBCR = IEN; /* Enable interface */ @@ -72,109 +73,169 @@ void i2c_init(void) void i2c_close(void) { MBCR = 0; + MBCR2 = 0; } -/** - * Writes bytes to the selected device. +/* + * Writes bytes to a I2C device. * - * Use device=1 for bus 1 at 0x40000280 - * Use device=2 for bus 2 at 0x80000440 - * - * Returns number of bytes successfully send or -1 if START failed + * Returns number of bytes successfully sent or a negative value on error. */ -int i2c_write(int device, unsigned char *buf, int count) +int i2c_write(volatile unsigned char *iface, unsigned char addr, + const unsigned char *buf, int count) { - int i; - int rc; + int i, rc; - rc = i2c_gen_start(device); + if ( ! count) + return 0; + + rc = i2c_start(iface); if (rc < 0) + return rc; + + rc = i2c_outb(iface, addr & 0xfe); + if (rc < 0) + return rc; + + for (i = 0; i < count; i++) { - logf("i2c: gen_start failed (d=%d)", device); - return rc*10 - 1; - } - - for (i=0; i= MAX_LOOP) - return -1; + *buf++ = iface[O_MBDR]; + } + return count; +} - count = 0; +/* --- Local functions - implementation --- */ - /* Wait for interrupt flag */ - while (!(regs[O_MBSR] & IFF) && count < MAX_LOOP) - count++; +/* Begin I2C session on the given interface. + * + * Returns 0 on success, negative value on error. + */ +int i2c_start(volatile unsigned char *iface) +{ + /* Wait for bus to become free */ + int j = MAX_LOOP; + while (--j && (iface[O_MBSR] & IBB)) + ; + if (!j) + { + logf("i2c: bus is busy (iface=%08x)", iface); + return -1; + } + + /* Generate START and prepare for write */ + iface[O_MBCR] |= (MSTA | TXAK | MTX); + + return 0; +} - if (count >= MAX_LOOP) +/* Wait for slave to act on given I2C interface. + * + * Returns 0 on success, negative value on error. + */ +int i2c_wait_for_slave(volatile unsigned char *iface) +{ + int j = MAX_LOOP; + while (--j && ! (iface[O_MBSR] & IFF)) + ; + if (!j) + { + logf("i2c: IFF not set (iface=%08x)", iface); + i2c_stop(iface); return -2; - - regs[O_MBSR] &= ~IFF; /* Clear interrupt flag */ - - if (!(regs[O_MBSR] & ICF)) /* Check that transfer is complete */ - return -3; - - if (regs[O_MBSR] & RXAK) /* Check that the byte has been ACKed */ - return -4; - + } + + /* Clear interrupt flag */ + iface[O_MBSR] &= ~IFF; + return 0; } - -/* Returns 0 on success, -1 on failure */ -int i2c_gen_start(int device) +/* Write the given byte to the given I2C interface. + * + * Returns 0 on success, negative value on error. + */ +int i2c_outb(volatile unsigned char *iface, unsigned char byte) { - volatile unsigned char *regs = i2c_get_addr(device); - long count = 0; - - /* Wait for bus to become free */ - while ((regs[O_MBSR] & IBB) && (count < MAX_LOOP)) - count++; - - if (count >= MAX_LOOP) - return -1; + int rc; - regs[O_MBCR] |= MSTA | MTX; /* Generate START */ + iface[O_MBDR] = byte; + rc = i2c_wait_for_slave(iface); + if (rc < 0) + return rc; + + /* Check that transfer is complete */ + if ( !(iface[O_MBSR] & ICF)) + { + logf("i2c: transfer error (iface=%08x)", iface); + i2c_stop(iface); + return -3; + } + + /* Check that the byte has been ACKed */ + if (iface[O_MBSR] & RXAK) + { + logf("i2c: no ACK (iface=%08x)", iface); + i2c_stop(iface); + return -4; + } + return 0; -} - -void i2c_gen_stop(int device) -{ - volatile unsigned char *regs = i2c_get_addr(device); - regs[O_MBCR] &= ~MSTA; /* Clear MSTA to generate STOP */ } - -volatile unsigned char *i2c_get_addr(int device) +/* End I2C session on the given interface. */ +inline void i2c_stop(volatile unsigned char *iface) { - if (device == 1) - return I2C_DEVICE_1; - - return I2C_DEVICE_2; + iface[O_MBCR] &= ~MSTA; } diff --git a/firmware/drivers/tlv320.c b/firmware/drivers/tlv320.c index 8ef32919ce..39cd2a5536 100644 --- a/firmware/drivers/tlv320.c +++ b/firmware/drivers/tlv320.c @@ -28,6 +28,7 @@ #include "string.h" #include "file.h" #include "buffer.h" +#include "audio.h" #include "i2c-coldfire.h" #include "tlv320.h" @@ -46,14 +47,13 @@ unsigned tlv320_regs[0xf]; void tlv320_write_reg(unsigned reg, unsigned value) { - unsigned char data[3]; + unsigned char data[2]; - data[0] = TLV320_ADDR; /* The register address is the high 7 bits and the data the low 9 bits */ - data[1] = (reg << 1) | ((value >> 8) & 1); - data[2] = value & 0xff; + data[0] = (reg << 1) | ((value >> 8) & 1); + data[1] = value & 0xff; - if (i2c_write(1, data, 3) != 3) + if (i2c_write(I2C_IFACE_0, TLV320_ADDR, data, 2) != 2) { logf("tlv320 error reg=0x%x", reg); return; @@ -73,15 +73,16 @@ void tlv320_init(void) /* Initialize all registers */ - tlv320_write_reg(REG_PC, 0x00); /* All ON */ - tlv320_set_linein_vol(0, 0); + tlv320_write_reg(REG_PC, PC_ADC|PC_MIC|PC_LINE); /* All ON except ADC, MIC and LINE */ + tlv320_set_recvol(0, 0, AUDIO_GAIN_MIC); + tlv320_set_recvol(0, 0, AUDIO_GAIN_LINEIN); tlv320_mute(true); tlv320_write_reg(REG_AAP, AAP_DAC|AAP_MICM); tlv320_write_reg(REG_DAP, 0x00); /* No deemphasis */ tlv320_write_reg(REG_DAIF, DAIF_IWL_16|DAIF_FOR_I2S); tlv320_set_headphone_vol(0, 0); tlv320_write_reg(REG_DIA, DIA_ACT); - tlv320_write_reg(REG_SRC, (8 << 2)); /* 44.1kHz */ + tlv320_write_reg(REG_SRC, (1 << 5)); /* 44.1kHz */ } /** @@ -114,18 +115,30 @@ void tlv320_set_headphone_vol(int vol_l, int vol_r) } /** - * Sets left and right linein volume (31(max) to 0(muted)) + * Set recording volume + * + * Line in : 0 .. 31 => Volume -34.5 .. 12 dB + * Mic (left): 0 .. 1 => Volume 0 .. 20 dB + * */ -void tlv320_set_linein_vol(int vol_l, int vol_r) +void tlv320_set_recvol(int left, int right, int type) { - unsigned value_l = tlv320_regs[REG_LLIV]; - unsigned value_r = tlv320_regs[REG_RLIV]; - - value_l |= LLIV_LIV(vol_l); - value_r |= RLIV_RIV(vol_r); - - tlv320_write_reg(REG_LLIV, value_l); - tlv320_write_reg(REG_RLIV, value_r); + if (type == AUDIO_GAIN_MIC) + { + unsigned value_aap = tlv320_regs[REG_AAP]; + + if (left) + value_aap |= AAP_MICB; /* Enable mic boost (20dB) */ + else + value_aap &= ~AAP_MICB; + + tlv320_write_reg(REG_AAP, value_aap); + + } else if (type == AUDIO_GAIN_LINEIN) + { + tlv320_write_reg(REG_LLIV, LLIV_LIV(left)); + tlv320_write_reg(REG_RLIV, RLIV_RIV(right)); + } } /** @@ -148,10 +161,11 @@ void tlv320_mute(bool mute) value_r = RHV_RHV(tlv320.vol_r); } - tlv320_write_reg(REG_LHV, value_r); + tlv320_write_reg(REG_LHV, value_l); tlv320_write_reg(REG_RHV, value_r); } +/* Nice shutdown of TLV320 codec */ void tlv320_close() { tlv320_write_reg(REG_PC, 0xFF); /* All OFF */ @@ -159,35 +173,66 @@ void tlv320_close() void tlv320_enable_recording(bool source_mic) { - unsigned value_pc = tlv320_regs[REG_PC]; - unsigned value_aap = tlv320_regs[REG_AAP]; - - /* select source*/ + unsigned value_daif = tlv320_regs[REG_DAIF]; + unsigned value_aap, value_pc; + if (source_mic) { - value_aap &= ~AAP_INSEL; - value_pc |= PC_MIC; + /* select mic and enable mic boost (20 dB) */ + value_aap = AAP_DAC | AAP_INSEL | AAP_MICB; + value_pc = PC_LINE; /* power down line-in */ } else { - value_aap |= AAP_INSEL; - value_pc |= PC_LINE; + value_aap = AAP_DAC | AAP_MICM; + value_pc = PC_MIC; /* power down mic */ } - /* poweron adc */ - value_pc |= PC_ADC; + tlv320_write_reg(REG_PC, value_pc); + sleep(HZ/8); tlv320_write_reg(REG_AAP, value_aap); - tlv320_write_reg(REG_PC, value_pc); + sleep(HZ/8); + + /* Enable MASTER mode (start sending I2S data to the CPU) */ + value_daif |= DAIF_MS; + tlv320_write_reg(REG_DAIF, value_daif); } - + void tlv320_disable_recording() { - unsigned value = tlv320_regs[REG_PC]; - - /* powerdown mic, linein and adc */ - value &= ~(PC_MIC | PC_LINE | PC_ADC); + unsigned value_pc = tlv320_regs[REG_PC]; + unsigned value_aap = tlv320_regs[REG_AAP]; + unsigned value_daif = tlv320_regs[REG_DAIF]; + + value_daif &= ~DAIF_MS; /* disable MASTER mode */ + tlv320_write_reg(REG_DAIF, value_daif); + + value_aap |= AAP_MICM; /* mute mic */ + tlv320_write_reg(REG_PC, value_aap); + + value_pc |= (PC_MIC|PC_LINE|PC_ADC); /* power down mic, line-in and adc */ + tlv320_write_reg(REG_PC, value_pc); + + sleep(HZ/8); +} - /* powerdown mic, linein and adc */ - tlv320_write_reg(REG_PC, value); +void tlv320_set_monitor(bool enable) +{ + unsigned value_aap, value_pc; + if (enable) + { + value_aap = AAP_BYPASS | AAP_MICM; + value_pc = (PC_MIC|PC_DAC|PC_ADC); /* power down mic, dac and adc */ + } + else + { + value_aap = AAP_DAC | AAP_MICM; + value_pc = (PC_MIC|PC_LINE|PC_ADC); /* power down mic, line-in and adc */ + } + tlv320_write_reg(REG_AAP, value_aap); + tlv320_write_reg(REG_PC, value_pc); + + sleep(HZ/8); } + diff --git a/firmware/drivers/uda1380.c b/firmware/drivers/uda1380.c index ef19dcf1c5..241a117385 100644 --- a/firmware/drivers/uda1380.c +++ b/firmware/drivers/uda1380.c @@ -76,14 +76,13 @@ unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] = /* Returns 0 if register was written or -1 if write failed */ int uda1380_write_reg(unsigned char reg, unsigned short value) { - unsigned char data[4]; + unsigned char data[3]; - data[0] = UDA1380_ADDR; - data[1] = reg; - data[2] = value >> 8; - data[3] = value & 0xff; + data[0] = reg; + data[1] = value >> 8; + data[2] = value & 0xff; - if (i2c_write(1, data, 4) != 4) + if (i2c_write(I2C_IFACE_0, UDA1380_ADDR, data, 3) != 3) { DEBUGF("uda1380 error reg=0x%x", reg); return -1; @@ -322,21 +321,20 @@ void uda1380_set_recvol(int left, int right, int type) { /* for this order we can combine both registers, making the glitch even smaller */ - unsigned char data[6]; + unsigned char data[5]; unsigned short value_dec; unsigned short value_pga; value_dec = DEC_VOLL(left) | DEC_VOLR(right); value_pga = (uda1380_regs[REG_PGA] & ~PGA_GAIN_MASK) | PGA_GAINL(left_ag) | PGA_GAINR(right_ag); - data[0] = UDA1380_ADDR; - data[1] = REG_DEC_VOL; - data[2] = value_dec >> 8; - data[3] = value_dec & 0xff; - data[4] = value_pga >> 8; - data[5] = value_pga & 0xff; + data[0] = REG_DEC_VOL; + data[1] = value_dec >> 8; + data[2] = value_dec & 0xff; + data[3] = value_pga >> 8; + data[4] = value_pga & 0xff; - if (i2c_write(1, data, 6) != 6) + if (i2c_write(I2C_IFACE_0, UDA1380_ADDR, data, 5) != 5) { DEBUGF("uda1380 error reg=combi rec gain"); } diff --git a/firmware/export/config-iaudiox5.h b/firmware/export/config-iaudiox5.h index d224b3b45e..cd77dc3c48 100644 --- a/firmware/export/config-iaudiox5.h +++ b/firmware/export/config-iaudiox5.h @@ -6,7 +6,7 @@ #define MODEL_NUMBER 10 /* define this if you have recording possibility */ -/*#define HAVE_RECORDING 1*/ +#define HAVE_RECORDING 1 /* define this if you have a bitmap LCD display */ #define HAVE_LCD_BITMAP 1 @@ -53,6 +53,11 @@ /* The number of bytes reserved for loadable plugins */ #define PLUGIN_BUFFER_SIZE 0x80000 +/* FM Tuner */ +#define CONFIG_TUNER TEA5767 +#define CONFIG_TUNER_XTAL 32768 + + #define BATTERY_CAPACITY_DEFAULT 950 /* default battery capacity */ #ifndef SIMULATOR diff --git a/firmware/export/fmradio_i2c.h b/firmware/export/fmradio_i2c.h index b7007a80dd..6483594d04 100644 --- a/firmware/export/fmradio_i2c.h +++ b/firmware/export/fmradio_i2c.h @@ -20,7 +20,7 @@ #ifndef FMRADIO_I2C_H #define FMRADIO_I2C_H -int fmradio_i2c_write(int address, const unsigned char* buf, int count); -int fmradio_i2c_read(int address, unsigned char* buf, int count); +int fmradio_i2c_write(unsigned char address, const unsigned char* buf, int count); +int fmradio_i2c_read(unsigned char address, unsigned char* buf, int count); #endif diff --git a/firmware/export/i2c-coldfire.h b/firmware/export/i2c-coldfire.h index d4a5781116..544a3169cf 100644 --- a/firmware/export/i2c-coldfire.h +++ b/firmware/export/i2c-coldfire.h @@ -26,10 +26,18 @@ #ifndef _I2C_COLDFIRE_H #define _I2C_COLDFIRE_H +#include "cpu.h" + void i2c_init(void); -int i2c_write(int device, unsigned char *buf, int count); +int i2c_read (volatile unsigned char *iface, unsigned char addr, + unsigned char *buf, int count); +int i2c_write(volatile unsigned char *iface, unsigned char addr, + const unsigned char *buf, int count); void i2c_close(void); +void i2c_adjust_prescale(int multiplier); +#define I2C_IFACE_0 ((volatile unsigned char *)&MADR) +#define I2C_IFACE_1 ((volatile unsigned char *)&MADR2) #define MAX_LOOP 0x100 /* TODO: select a better value */ diff --git a/firmware/export/sound.h b/firmware/export/sound.h index a49cb99263..33175e4166 100644 --- a/firmware/export/sound.h +++ b/firmware/export/sound.h @@ -36,7 +36,7 @@ enum { SOUND_MDB_ENABLE, SOUND_SUPERBASS, #endif -#if CONFIG_CODEC == MAS3587F || defined(HAVE_UDA1380) +#if CONFIG_CODEC == MAS3587F || defined(HAVE_UDA1380) || defined(HAVE_TLV320) SOUND_LEFT_GAIN, SOUND_RIGHT_GAIN, SOUND_MIC_GAIN, diff --git a/firmware/export/tlv320.h b/firmware/export/tlv320.h index 93a79780c0..45ebfee569 100644 --- a/firmware/export/tlv320.h +++ b/firmware/export/tlv320.h @@ -26,11 +26,12 @@ extern void tlv320_init(void); extern void tlv320_reset(void); extern void tlv320_enable_output(bool enable); extern void tlv320_set_headphone_vol(int vol_l, int vol_r); -extern void tlv320_set_linein_vol(int vol_l, int vol_r); +extern void tlv320_set_recvol(int left, int right, int type); extern void tlv320_mute(bool mute); extern void tlv320_close(void); extern void tlv320_enable_recording(bool source_mic); extern void tlv320_disable_recording(void); +extern void tlv320_set_monitor(bool enable); #define HEADPHONE_MUTE 0x30 /* 0110000 = -73db */ diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c index 2d9c65a7e4..fee2bbd35b 100644 --- a/firmware/pcm_record.c +++ b/firmware/pcm_record.c @@ -31,7 +31,12 @@ #include "cpu.h" #include "i2c.h" #include "power.h" +#ifdef HAVE_UDA1380 #include "uda1380.h" +#endif +#ifdef HAVE_TLV320 +#include "tlv320.h" +#endif #include "system.h" #include "usb.h" @@ -51,14 +56,14 @@ extern int boost_counter; /* used for boost check */ /***************************************************************************/ -static volatile bool is_recording; /* We are recording */ -static volatile bool is_stopping; /* Are we going to stop */ -static volatile bool is_paused; /* We have paused */ -static volatile bool is_error; /* An error has occured */ +static bool is_recording; /* We are recording */ +static bool is_stopping; /* Are we going to stop */ +static bool is_paused; /* We have paused */ +static bool is_error; /* An error has occured */ -static volatile unsigned long num_rec_bytes; /* Num bytes recorded */ -static volatile unsigned long num_file_bytes; /* Num bytes written to current file */ -static volatile int error_count; /* Number of DMA errors */ +static unsigned long num_rec_bytes; /* Num bytes recorded */ +static unsigned long num_file_bytes; /* Num bytes written to current file */ +static int error_count; /* Number of DMA errors */ static long record_start_time; /* Value of current_tick when recording was started */ static long pause_start_time; /* Value of current_tick when pause was started */ @@ -69,7 +74,7 @@ static int rec_source; /* Current recording source */ static int wav_file; static char recording_filename[MAX_PATH]; -static volatile bool init_done, close_done, record_done, stop_done, pause_done, resume_done, new_file_done; +static bool init_done, close_done, record_done, stop_done, pause_done, resume_done, new_file_done; static short peak_left, peak_right; @@ -90,16 +95,23 @@ static unsigned int rec_buffer_offset; static unsigned char *rec_buffer; /* Circular recording buffer */ static int num_chunks; /* Number of chunks available in rec_buffer */ - +#ifdef IAUDIO_X5 +#define SET_IIS_PLAY(x) IIS1CONFIG = (x); +#define SET_IIS_REC(x) IIS1CONFIG = (x); +#else +#define SET_IIS_PLAY(x) IIS2CONFIG = (x); +#define SET_IIS_REC(x) IIS1CONFIG = (x); +#endif + /* Overrun occures when DMA needs to write a new chunk and write_index == read_index Solution to this is to optimize pcmrec_callback, use cpu_boost or save to disk more often. */ -static volatile int write_index; /* Current chunk the DMA is writing to */ -static volatile int read_index; /* Oldest chunk that is not written to disk */ -static volatile int read2_index; /* Latest chunk that has not been converted to little endian */ +static int write_index; /* Current chunk the DMA is writing to */ +static int read_index; /* Oldest chunk that is not written to disk */ +static int read2_index; /* Latest chunk that has not been converted to little endian */ static long pre_record_ticks; /* pre-record time expressed in ticks */ static int pre_record_chunks; /* pre-record time expressed in chunks */ @@ -137,7 +149,7 @@ void pcm_rec_init(void) /* Initializes recording: - * - Set up the UDA1380 for recording + * - Set up the UDA1380/TLV320 for recording * - Prepare for DMA transfers */ @@ -292,14 +304,26 @@ void audio_set_recording_options(int frequency, int quality, case 0: /* Generate int. when 6 samples in FIFO, PDIR2 src = IIS1recv */ DATAINCONTROL = 0xc020; + +#ifdef HAVE_UDA1380 uda1380_enable_recording(true); +#endif +#ifdef HAVE_TLV320 + tlv320_enable_recording(true); +#endif break; /* line-in */ case 1: /* Generate int. when 6 samples in FIFO, PDIR2 src = IIS1recv */ DATAINCONTROL = 0xc020; + +#ifdef HAVE_UDA1380 uda1380_enable_recording(false); +#endif +#ifdef HAVE_TLV320 + tlv320_enable_recording(false); +#endif break; #ifdef HAVE_SPDIF_IN /* SPDIF */ @@ -322,7 +346,8 @@ void audio_set_recording_options(int frequency, int quality, /* Monitoring: route the signals through the coldfire audio interface. */ - IIS2CONFIG = 0x800; /* Reset before reprogram */ + SET_IIS_PLAY(0x800); /* Reset before reprogram */ + #ifdef HAVE_SPDIF_IN if (source == 2) { /* SCLK2 = Audioclk/4 (can't use EBUin clock), TXSRC = EBU1rcv, 64 bclk/wclk */ @@ -340,21 +365,27 @@ void audio_set_recording_options(int frequency, int quality, } #else /* SCLK2 follow IIS1 (UDA clock), TXSRC = IIS1rcv, 64 bclk/wclk */ - IIS2CONFIG = (8 << 12) | (4 << 8) | (4 << 2); + SET_IIS_PLAY( (8 << 12) | (4 << 8) | (4 << 2) ); #endif } /** * Note that microphone is mono, only left value is used - * See uda1380_set_recvol() for exact ranges. + * See {uda1380,tlv320}_set_recvol() for exact ranges. * * @param type 0=line-in (radio), 1=mic * */ void audio_set_recording_gain(int left, int right, int type) { + //logf("rcmrec: t=%d l=%d r=%d", type, left, right); +#ifdef HAVE_UDA1380 uda1380_set_recvol(left, right, type); +#endif +#ifdef HAVE_TLV320 + tlv320_set_recvol(left, right, type); +#endif } @@ -987,7 +1018,7 @@ static void pcmrec_init(void) logf("num_chunks: %d", num_chunks); - IIS1CONFIG = 0x800; /* Stop any playback */ + SET_IIS_PLAY(0x800); /* Stop any playback */ AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */ DATAINCONTROL = 0xc000; /* Generate Interrupt when 6 samples in fifo */ @@ -1007,7 +1038,12 @@ static void pcmrec_init(void) static void pcmrec_close(void) { +#ifdef HAVE_UDA1380 uda1380_disable_recording(); +#endif +#ifdef HAVE_TLV320 + tlv320_disable_recording(); +#endif #ifdef HAVE_SPDIF_POWER spdif_power_enable(spdif_power_setting); @@ -1091,7 +1127,7 @@ void pcm_rec_mux(int source) or_l(0x40000000, &GPIO_ENABLE); or_l(0x40000000, &GPIO_FUNCTION); -#else +#elif defined(IRIVER_H100_SERIES) if(source == 0) and_l(~0x00800000, &GPIO_OUT); /* Line In */ else @@ -1099,5 +1135,16 @@ void pcm_rec_mux(int source) or_l(0x00800000, &GPIO_ENABLE); or_l(0x00800000, &GPIO_FUNCTION); + +#elif defined(IAUDIO_X5) + if(source == 0) + or_l((1<<29), &GPIO_OUT); /* Line In */ + else + and_l(~(1<<29), &GPIO_OUT); /* FM radio */ + + or_l((1<<29), &GPIO_ENABLE); + or_l((1<<29), &GPIO_FUNCTION); + + /* iAudio x5 */ #endif } diff --git a/firmware/sound.c b/firmware/sound.c index 057cfc0995..5e4cd5db48 100644 --- a/firmware/sound.c +++ b/firmware/sound.c @@ -111,7 +111,11 @@ static const struct sound_settings_info sound_settings_table[] = { [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL}, [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL}, [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16, NULL}, -#endif +#elif defined(HAVE_TLV320) + [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 31, 23, NULL}, + [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 31, 23, NULL}, + [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 1, 1, NULL}, + #endif }; const char *sound_unit(int setting) @@ -901,6 +905,25 @@ int sound_val2phys(int setting, int value) break; } return result; +#elif defined(HAVE_TLV320) + int result = 0; + + switch(setting) + { + case SOUND_LEFT_GAIN: + case SOUND_RIGHT_GAIN: + result = (value - 23) * 15; /* (x - 23)/1.5 *10 */ + break; + + case SOUND_MIC_GAIN: + result = value * 200; /* 0 or 20 dB */ + break; + + default: + result = value; + break; + } + return result; #else (void)setting; return value; diff --git a/firmware/target/coldfire/iaudio/x5/power-x5.c b/firmware/target/coldfire/iaudio/x5/power-x5.c index 14236cbb37..4199993637 100644 --- a/firmware/target/coldfire/iaudio/x5/power-x5.c +++ b/firmware/target/coldfire/iaudio/x5/power-x5.c @@ -64,6 +64,20 @@ void power_off(void) yield(); } +static bool powered = false; + +bool radio_powered() +{ + return powered; +} + +bool radio_power(bool status) +{ + bool old_status = powered; + powered = status; + return old_status; +} + #else bool charger_inserted(void) -- cgit v1.2.3