From cc50c149e9452e7c8ea199fd72f7458ead96bad7 Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Mon, 13 Nov 2006 23:21:54 +0000 Subject: [PATCH] H100/General: HAL for S/PDIF and refinement/bufixes in optical output powering/source selection. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11523 a1c6a512-1295-4272-9138-f99709370657 --- apps/debug_menu.c | 15 +++- apps/recorder/recording.c | 38 ++++----- firmware/SOURCES | 3 + firmware/export/audio.h | 4 - firmware/export/power.h | 1 + firmware/export/spdif.h | 36 ++++++++ firmware/pcm_record.c | 55 ++---------- .../target/coldfire/iriver/h100/power-h100.c | 25 +++++- .../target/coldfire/iriver/h100/spdif-h100.c | 83 +++++++++++++++++++ firmware/target/coldfire/pcm-coldfire.c | 36 ++------ 10 files changed, 183 insertions(+), 113 deletions(-) create mode 100644 firmware/export/spdif.h create mode 100644 firmware/target/coldfire/iriver/h100/spdif-h100.c diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 4620adaaec..e1bb5ccb9f 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c @@ -74,6 +74,9 @@ #if CONFIG_CODEC == SWCODEC #include "pcmbuf.h" #include "pcm_playback.h" +#if defined(HAVE_SPDIF_OUT) || defined(HAVE_SPDIF_IN) +#include "spdif.h" +#endif #endif #ifdef IAUDIO_X5 @@ -774,14 +777,17 @@ bool dbg_spdif(void) unsigned int interruptstat; bool valnogood, symbolerr, parityerr; bool done = false; + bool spdif_src_on; + int spdif_source = spdif_get_output_source(&spdif_src_on); + spdif_set_output_source(AUDIO_SRC_SPDIF, true); lcd_setmargins(0, 0); lcd_clear_display(); lcd_setfont(FONT_SYSFIXED); + #ifdef HAVE_SPDIF_POWER spdif_power_enable(true); /* We need SPDIF power for both sending & receiving */ #endif - PHASECONFIG = 0x34; /* Gain = 3*2^13, source = EBUIN */ while (!done) { @@ -914,15 +920,18 @@ bool dbg_spdif(void) #ifndef SIMULATOR snprintf(buf, sizeof(buf), "Measured freq: %ldHz", - (long)((long long)FREQMEAS*CPU_FREQ/((1 << 15)*3*(1 << 13))/128)); + spdif_measure_frequency()); lcd_puts(0, line++, buf); #endif lcd_update(); if (action_userabort(HZ/10)) - return false; + break; } + + spdif_set_output_source(spdif_source, spdif_src_on); + #ifdef HAVE_SPDIF_POWER spdif_power_enable(global_settings.spdif_enable); #endif diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c index d38856db23..4c2b00c33c 100644 --- a/apps/recorder/recording.c +++ b/apps/recorder/recording.c @@ -34,7 +34,10 @@ #include "pcm_playback.h" #include "playback.h" #include "enc_config.h" +#if defined(HAVE_SPDIF_IN) || defined(HAVE_SPDIF_OUT) +#include "spdif.h" #endif +#endif /* CONFIG_CODEC == SWCODEC */ #ifdef HAVE_UDA1380 #include "uda1380.h" #endif @@ -587,12 +590,6 @@ static void rec_boost(bool state) #define ac_set_monitor tlv320_set_monitor #endif -#ifdef HAVE_SPDIF_IN -#define rec_spdif_set_monitor(m) audio_spdif_set_monitor(m) -#else -#define rec_spdif_set_monitor(m) -#endif - void rec_set_source(int source, unsigned flags) { /* Prevent pops from unneeded switching */ @@ -613,15 +610,23 @@ void rec_set_source(int source, unsigned flags) /* Always boost for SPDIF */ if ((source == AUDIO_SRC_SPDIF) != (source == last_source)) rec_boost(source == AUDIO_SRC_SPDIF); +#endif /* HAVE_SPDIF_IN */ #ifdef HAVE_SPDIF_POWER /* Check if S/PDIF output power should be switched off or on. NOTE: assumes both optical in and out is controlled by the same power source, which is the case on H1x0. */ spdif_power_enable((source == AUDIO_SRC_SPDIF) || - audio_get_spdif_power_setting()); + global_settings.spdif_enable); + /* Set the appropriate feed for spdif output */ +#ifdef HAVE_SPDIF_OUT + spdif_set_output_source(source, global_settings.spdif_enable); #endif +#else /* !HAVE_SPDIF_POWER */ +#ifdef HAVE_SPDIF_OUT + spdif_set_output_source(source, true); #endif +#endif /* !HAVE_SPDIF_POWER */ /** Tuner **/ #ifdef CONFIG_TUNER @@ -645,7 +650,6 @@ void rec_set_source(int source, unsigned flags) ac_disable_recording(); ac_set_monitor(false); pcm_rec_mux(0); /* line in */ - rec_spdif_set_monitor(-1); /* silence it */ break; case AUDIO_SRC_MIC: /* recording only */ @@ -653,7 +657,6 @@ void rec_set_source(int source, unsigned flags) break; ac_enable_recording(true); /* source mic */ pcm_rec_mux(0); /* line in */ - rec_spdif_set_monitor(0); break; case AUDIO_SRC_LINEIN: /* recording only */ @@ -661,7 +664,6 @@ void rec_set_source(int source, unsigned flags) break; pcm_rec_mux(0); /* line in */ ac_enable_recording(false); /* source line */ - rec_spdif_set_monitor(0); break; #ifdef HAVE_SPDIF_IN @@ -669,7 +671,6 @@ void rec_set_source(int source, unsigned flags) if (source == last_source) break; ac_disable_recording(); - audio_spdif_set_monitor(1); break; #endif /* HAVE_SPDIF_IN */ @@ -690,7 +691,6 @@ void rec_set_source(int source, unsigned flags) break; /* I2S recording and playback */ uda1380_enable_recording(false); /* source line */ - uda1380_set_monitor(true); #endif #ifdef HAVE_TLV320 /* I2S recording and analog playback */ @@ -707,8 +707,6 @@ void rec_set_source(int source, unsigned flags) tlv320_set_monitor(true); /* analog bypass */ } #endif - - rec_spdif_set_monitor(0); break; /* #elif defined(CONFIG_TUNER) */ /* Have radio but cannot record it */ @@ -745,18 +743,10 @@ void rec_set_recording_options(struct audio_recording_options *options) #if CONFIG_CODEC != SWCODEC if (global_settings.rec_prerecord_time) talk_buffer_steal(); /* will use the mp3 buffer */ -#endif - -#ifdef HAVE_SPDIF_IN -#ifdef HAVE_SPDIF_POWER - audio_set_spdif_power_setting(global_settings.spdif_enable); -#endif -#endif - -#if CONFIG_CODEC == SWCODEC +#else /* == SWOCODEC */ rec_set_source(options->rec_source, options->rec_source_flags | SRCF_RECORDING); -#endif +#endif /* CONFIG_CODEC != SWCODEC */ audio_set_recording_options(options); } diff --git a/firmware/SOURCES b/firmware/SOURCES index 369b260c8e..73d68fee91 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -366,6 +366,9 @@ target/coldfire/iriver/h100/backlight-h100.c target/coldfire/iriver/h100/button-h100.c target/coldfire/iriver/h100/lcd-as-h100.S target/coldfire/iriver/h100/lcd-h100.c +#ifndef BOOTLOADER +target/coldfire/iriver/h100/spdif-h100.c +#endif target/coldfire/iriver/h100/usb-h100.c #endif /* SIMULATOR */ #endif /* IRIVER_H100_SERIES */ diff --git a/firmware/export/audio.h b/firmware/export/audio.h index d3f544de94..42d94a9158 100644 --- a/firmware/export/audio.h +++ b/firmware/export/audio.h @@ -185,10 +185,6 @@ unsigned char *audio_get_recording_buffer(size_t *buffer_size); #endif /* HAVE_RECORDING */ #ifdef HAVE_SPDIF_IN -#ifdef HAVE_SPDIF_POWER -void audio_set_spdif_power_setting(bool on); -bool audio_get_spdif_power_setting(void); -#endif /* returns index into rec_master_sampr_list */ int audio_get_spdif_sample_rate(void); /* > 0: monitor EBUin, 0: Monitor IISrecv, <0: reset only */ diff --git a/firmware/export/power.h b/firmware/export/power.h index dc6c09d9f9..911ae1dd29 100644 --- a/firmware/export/power.h +++ b/firmware/export/power.h @@ -44,6 +44,7 @@ bool ide_powered(void); #ifdef HAVE_SPDIF_POWER void spdif_power_enable(bool on); +bool spdif_powered(void); #endif #ifdef CONFIG_TUNER diff --git a/firmware/export/spdif.h b/firmware/export/spdif.h new file mode 100644 index 0000000000..f4712fb88f --- /dev/null +++ b/firmware/export/spdif.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Michal Sevakis + * Based on the work of Thom Johansen + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef SPDIF_H +#define SPDIF_H + +/* Initialize the S/PDIF driver */ +void spdif_init(void); +/* Return the S/PDIF frequency in herz - unrounded */ +unsigned long spdif_measure_frequency(void); +#ifdef HAVE_SPDIF_OUT +/* Set the S/PDIF audio feed - Use AUDIO_SRC_* values - + will be off if not powered or !on */ +void spdif_set_output_source(int source, bool on); +/* Return the last set S/PDIF audio source - literally the last value passed + to spdif_set_monitor regardless of power state */ +int spdif_get_output_source(bool *src_on); +#endif /* HAVE_SPDIF_OUT */ + +#endif /* SPDIF_H */ diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c index 25f1f1ef64..04289f36ec 100644 --- a/firmware/pcm_record.c +++ b/firmware/pcm_record.c @@ -34,6 +34,9 @@ #include "audio.h" #include "sound.h" #include "id3.h" +#ifdef HAVE_SPDIF_IN +#include "spdif.h" +#endif /***************************************************************************/ @@ -349,18 +352,6 @@ unsigned long audio_num_recorded_bytes(void) } /* audio_num_recorded_bytes */ #ifdef HAVE_SPDIF_IN -/* Return current SPDIF sample rate */ -static unsigned long measure_spdif_sample_rate(void) -{ - /* The following formula is specified in MCF5249 user's manual section - * 17.6.1. The 128 divide is because of the fact that the SPDIF clock is - * the sample rate times 128. Keep "3*(1 << 13)" part in sync with - * PHASECONFIG setup in pcm_init_recording in pcm-coldfire.c. - */ - return (unsigned long)((unsigned long long)FREQMEAS*CPU_FREQ / - ((1 << 15)*3*(1 << 13))/128); -} /* measure_spdif_sample_rate */ - /** * Return SPDIF sample rate index in audio_master_sampr_list. Since we base * our reading on the actual SPDIF sample rate (which might be a bit @@ -369,47 +360,11 @@ static unsigned long measure_spdif_sample_rate(void) */ int audio_get_spdif_sample_rate(void) { - unsigned long measured_rate = measure_spdif_sample_rate(); + unsigned long measured_rate = spdif_measure_frequency(); /* Find which SPDIF sample rate we're closest to. */ return round_value_to_list32(measured_rate, audio_master_sampr_list, SAMPR_NUM_FREQ, false); } /* audio_get_spdif_sample_rate */ - -#ifdef HAVE_SPDIF_POWER -static bool spdif_power_setting; - -void audio_set_spdif_power_setting(bool on) -{ - spdif_power_setting = on; -} /* audio_set_spdif_power_setting */ - -bool audio_get_spdif_power_setting(void) -{ - return spdif_power_setting; -} /* audio_get_spdif_power_setting */ -#endif - -void audio_spdif_set_monitor(int monitor_spdif) -{ - EBU1CONFIG = 0x800; /* Reset before reprogram */ - - if (monitor_spdif > 0) - { -#ifdef HAVE_SPDIF_POWER - EBU1CONFIG = spdif_power_setting ? (1 << 2) : 0; - /* Input source is EBUin1, Feed-through monitoring if desired */ -#else - EBU1CONFIG = (1 << 2); - /* Input source is EBUin1, Feed-through monitoring */ -#endif - } - else if (monitor_spdif == 0) - { - /* SCLK2, TXSRC = IIS1recv, validity, normal operation */ - EBU1CONFIG = (7 << 12) | (4 << 8) | (1 << 5) | (5 << 2); - } -} /* audio_spdif_set_monitor */ - #endif /* HAVE_SPDIF_IN */ /** @@ -434,7 +389,7 @@ void audio_set_recording_options(struct audio_recording_options *options) if (rec_source == AUDIO_SRC_SPDIF) { /* must measure SPDIF sample rate before configuring codecs */ - unsigned long sr = measure_spdif_sample_rate(); + unsigned long sr = spdif_measure_frequency(); /* round to master list for SPDIF rate */ int index = round_value_to_list32(sr, audio_master_sampr_list, SAMPR_NUM_FREQ, false); diff --git a/firmware/target/coldfire/iriver/h100/power-h100.c b/firmware/target/coldfire/iriver/h100/power-h100.c index 0714ab2d3f..9effeef7c8 100644 --- a/firmware/target/coldfire/iriver/h100/power-h100.c +++ b/firmware/target/coldfire/iriver/h100/power-h100.c @@ -22,6 +22,7 @@ #include "kernel.h" #include "system.h" #include "power.h" +#include "spdif.h" #ifdef CONFIG_TUNER @@ -85,8 +86,23 @@ void spdif_power_enable(bool on) and_l(~0x01000000, &GPIO1_OUT); else or_l(0x01000000, &GPIO1_OUT); -} + +#ifndef BOOTLOADER + /* Make sure the feed is reset */ + spdif_set_output_source(spdif_get_output_source(NULL), true); #endif +} + +bool spdif_powered(void) +{ + bool state = (GPIO1_READ & 0x01000000)?false:true; +#ifdef SPDIF_POWER_INVERTED + return !state; +#else + return state; +#endif /* SPDIF_POWER_INVERTED */ +} +#endif /* HAVE_SPDIF_POWER */ void ide_power_enable(bool on) { @@ -96,13 +112,11 @@ void ide_power_enable(bool on) or_l(0x80000000, &GPIO_OUT); } - bool ide_powered(void) { return (GPIO_OUT & 0x80000000)?false:true; } - void power_off(void) { set_irq_level(HIGHEST_IRQ_LEVEL); @@ -138,6 +152,11 @@ void spdif_power_enable(bool on) { (void)on; } + +bool spdif_powered(void) +{ + return false; +} #endif #endif /* SIMULATOR */ diff --git a/firmware/target/coldfire/iriver/h100/spdif-h100.c b/firmware/target/coldfire/iriver/h100/spdif-h100.c new file mode 100644 index 0000000000..20e5bc3c45 --- /dev/null +++ b/firmware/target/coldfire/iriver/h100/spdif-h100.c @@ -0,0 +1,83 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Michal Sevakis + * Based on the work of Thom Johansen + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include +#include "config.h" +#include "cpu.h" +#include "power.h" +#include "system.h" +#include "audio.h" +#include "spdif.h" + +static int spdif_source = AUDIO_SRC_PLAYBACK; +static int spdif_on = false; + +/* Initialize the S/PDIF driver */ +void spdif_init(void) +{ + /* PHASECONFIG setup: gain = 3*2^13, source = EBUIN */ + PHASECONFIG = (6 << 3) | (4 << 0); + spdif_set_output_source(AUDIO_SRC_PLAYBACK, true); +} + +/* Return the S/PDIF frequency in herz - unrounded */ +unsigned long spdif_measure_frequency(void) +{ + /* The following formula is specified in MCF5249 user's manual section + * 17.6.1. The 128 divide is because of the fact that the SPDIF clock is + * the sample rate times 128. + */ + return (unsigned long)((unsigned long long)FREQMEAS*CPU_FREQ / + ((1 << 15)*3*(1 << 13))/128); +} /* spdif_measure_frequency */ + +/* Set the S/PDIF audio feed */ +void spdif_set_output_source(int source, bool src_on) +{ + static const unsigned short ebu1_config[] = + { + /* SCLK2, TXSRC = PDOR3, validity, normal operation */ + [AUDIO_SRC_PLAYBACK+1] = (7 << 12) | (3 << 8) | (1 << 5) | (5 << 2), + /* Input source is EBUin1, Feed-through monitoring */ + [AUDIO_SRC_SPDIF+1] = (1 << 2), + /* SCLK2, TXSRC = IIS1recv, validity, normal operation */ + [AUDIO_SRC_MIC+1] = (7 << 12) | (4 << 8) | (1 << 5) | (5 << 2), + [AUDIO_SRC_LINEIN+1] = (7 << 12) | (4 << 8) | (1 << 5) | (5 << 2), + [AUDIO_SRC_FMRADIO+1] = (7 << 12) | (4 << 8) | (1 << 5) | (5 << 2), + }; + + if ((unsigned)source >= ARRAYLEN(ebu1_config)) + source = AUDIO_SRC_PLAYBACK; + + EBU1CONFIG = 0x800; /* Reset before reprogram */ + + spdif_source = source; + spdif_on = spdif_powered() && src_on; + + /* Tranceiver must be powered or else monitoring will be disabled */ + EBU1CONFIG = spdif_on ? ebu1_config[source + 1] : 0; +} /* spdif_set_output_source */ + +/* Return the last set S/PDIF audio source */ +int spdif_get_output_source(bool *src_on) +{ + if (src_on != NULL) + *src_on = spdif_on; + return spdif_source; +} /* spdif_get_output_source */ diff --git a/firmware/target/coldfire/pcm-coldfire.c b/firmware/target/coldfire/pcm-coldfire.c index 6b92f9cc14..0048c9990c 100644 --- a/firmware/target/coldfire/pcm-coldfire.c +++ b/firmware/target/coldfire/pcm-coldfire.c @@ -26,6 +26,9 @@ #elif defined(HAVE_TLV320) #include "tlv320.h" #endif +#if defined(HAVE_SPDIF_IN) || defined(HAVE_SPDIF_OUT) +#include "spdif.h" +#endif /* Avoid further #ifdef's for some codec functions */ #if defined(HAVE_UDA1380) @@ -69,10 +72,6 @@ static int rec_peak_left, rec_peak_right; #define IIS_CONFIG IIS2CONFIG #define PLLCR_SET_AUDIO_BITS_DEFPARM \ ((freq_ent[FPARM_CLSEL] << 28) | (3 << 22)) - -#ifdef HAVE_SPDIF_OUT -#define EBU_DEFPARM ((7 << 12) | (3 << 8) | (1 << 5) | (5 << 2)) -#endif #endif /** Sample rates **/ @@ -229,11 +228,6 @@ void pcm_play_dma_start(const void *addr, size_t size) pcm_playing = true; - /* Reset the audio FIFO */ -#ifdef HAVE_SPDIF_OUT - EBU1CONFIG = IIS_RESET | EBU_DEFPARM; -#endif - /* Set up DMA transfer */ SAR0 = (unsigned long)addr; /* Source address */ DAR0 = (unsigned long)&PDOR3; /* Destination address */ @@ -242,11 +236,6 @@ void pcm_play_dma_start(const void *addr, size_t size) /* Enable the FIFO and force one write to it */ pcm_apply_settings(false); - /* Also send the audio to S/PDIF */ -#ifdef HAVE_SPDIF_OUT - EBU1CONFIG = EBU_DEFPARM; -#endif - DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_SINC | DMA_SSIZE(3) | DMA_START; } /* pcm_play_dma_start */ @@ -263,10 +252,6 @@ void pcm_play_dma_stop(void) /* Reset the FIFO */ pcm_apply_settings(false); - -#ifdef HAVE_SPDIF_OUT - EBU1CONFIG = IIS_RESET | EBU_DEFPARM; -#endif } /* pcm_play_dma_stop */ void pcm_init(void) @@ -291,6 +276,10 @@ void pcm_init(void) /* Prevent pops (resets DAC to zero point) */ SET_IIS_CONFIG(IIS_DEFPARM | IIS_RESET); +#if defined(HAVE_SPDIF_IN) || defined(HAVE_SPDIF_OUT) + spdif_init(); +#endif + /* Initialize default register values. */ ac_init(); @@ -417,11 +406,6 @@ void pcm_init_recording(void) DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */ DMAROUTE = (DMAROUTE & 0xffff00ff) | DMA1_REQ_AUDIO_2; -#ifdef HAVE_SPDIF_IN - /* PHASECONFIG setup: gain = 3*2^13, source = EBUIN */ - PHASECONFIG = (6 << 3) | (4 << 0); -#endif - pcm_rec_dma_stop(); ICR7 = (7 << 2); /* Enable interrupt at level 7, priority 0 */ @@ -506,18 +490,12 @@ void pcm_play_pause_pause(void) /* Disable DMA peripheral request. */ DCR0 &= ~DMA_EEXT; pcm_apply_settings(true); -#ifdef HAVE_SPDIF_OUT - EBU1CONFIG = EBU_DEFPARM; -#endif } /* pcm_play_pause_pause */ void pcm_play_pause_unpause(void) { /* Enable the FIFO and force one write to it */ pcm_apply_settings(false); -#ifdef HAVE_SPDIF_OUT - EBU1CONFIG = EBU_DEFPARM; -#endif DCR0 |= DMA_EEXT | DMA_START; } /* pcm_play_pause_unpause */