diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 93004d818a..736c2054d1 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c @@ -1942,11 +1942,10 @@ static bool dbg_save_roms(void) #ifndef SIMULATOR #if CONFIG_TUNER -int radio_lines = 0; static int radio_callback(int btn, struct gui_synclist *lists) { - (void)btn;(void)lists; - radio_lines = 0; + int radio_lines = 0; + if (radio_hardware_present()) { snprintf(debug_list_messages[radio_lines++], DEBUG_MSG_LEN, @@ -1966,10 +1965,14 @@ static int radio_callback(int btn, struct gui_synclist *lists) "if_set: %d Hz", (lv24020lp_get(LV24020LP_IF_SET) ) ); snprintf(debug_list_messages[radio_lines++], DEBUG_MSG_LEN, "sd_set: %d Hz", (lv24020lp_get(LV24020LP_SD_SET) ) ); + + if (btn != ACTION_STD_CANCEL) + btn = ACTION_REDRAW; #endif #if (CONFIG_TUNER & S1A0903X01) snprintf(debug_list_messages[radio_lines++], DEBUG_MSG_LEN, "Samsung regs: %08X", s1a0903x01_get(RADIO_ALL)); + /* This one doesn't return dynamic data atm */ #endif #if (CONFIG_TUNER & TEA5767) struct tea5767_dbg_info info; @@ -1985,16 +1988,21 @@ static int radio_callback(int btn, struct gui_synclist *lists) (unsigned)info.write_regs[0], (unsigned)info.write_regs[1], (unsigned)info.write_regs[2], (unsigned)info.write_regs[3], (unsigned)info.write_regs[4]); + + if (btn != ACTION_STD_CANCEL) + btn = ACTION_REDRAW; #endif - btn = ACTION_REDRAW; + + gui_synclist_set_nb_items(lists, radio_lines); } else - snprintf(debug_list_messages[radio_lines++], DEBUG_MSG_LEN, "HW detected: no"); + snprintf(debug_list_messages[0], DEBUG_MSG_LEN, "HW detected: no"); + return btn; } static bool dbg_fm_radio(void) { - dbg_list("FM Radio",radio_lines, 1, + dbg_list("FM Radio", 1, 1, radio_callback, dbg_listmessage_getname); return false; } diff --git a/firmware/drivers/tuner/lv24020lp.c b/firmware/drivers/tuner/lv24020lp.c index 9ec68f9a27..79d38443f2 100644 --- a/firmware/drivers/tuner/lv24020lp.c +++ b/firmware/drivers/tuner/lv24020lp.c @@ -24,6 +24,7 @@ #include "thread.h" #include "kernel.h" #include "tuner.h" /* tuner abstraction interface */ +#include "power.h" #include "fmradio.h" /* physical interface driver */ #include "sound.h" #include "pp5024.h" @@ -31,6 +32,8 @@ #ifndef BOOTLOADER +static struct mutex tuner_mtx; + #if 0 /* define to enable tuner logging */ #define SANYO_TUNER_LOG @@ -338,6 +341,10 @@ static void lv24020lp_write(unsigned int address, unsigned int data) break; } + /* Check if interface is turned on */ + if (!(tuner_status & TUNER_POWERED)) + return; + address = lv24020lp_begin_write(address); /* data first */ @@ -365,6 +372,10 @@ static unsigned int lv24020lp_read(unsigned int address) int i; unsigned int toread; + /* Check if interface is turned on */ + if (!(tuner_status & TUNER_POWERED)) + return 0; + address = lv24020lp_begin_write(address); /* address */ @@ -433,9 +444,6 @@ static int tuner_measure(unsigned char type, int scale, int duration) { int64_t finval; - if (!tuner_awake()) - return 0; - /* enable measuring */ lv24020lp_write_or(MSRC_SEL, type); lv24020lp_write_and(CNT_CTRL, ~CNT_SEL); @@ -463,19 +471,20 @@ static int tuner_measure(unsigned char type, int scale, int duration) else finval = scale*finval / duration; + /* This function takes a loooong time and other stuff needs + running by now */ + yield(); + return (int)finval; } /* set the FM oscillator frequency */ -static void set_frequency(int freq) +static bool set_frequency(int freq) { int coef, cap_value, osc_value; int f1, f2, x1, x2; int count; - if (!tuner_awake()) - return; - TUNER_LOG_OPEN(); TUNER_LOG("set_frequency(%d)\n", freq); @@ -579,6 +588,8 @@ static void set_frequency(int freq) TUNER_LOG("\n"); TUNER_LOG_SYNC(); + + return true; } static void fine_step_tune(int (*setcmp)(int regval), int regval, int step) @@ -639,10 +650,10 @@ static int if_setcmp(int regval) /* This register is bounces around by a few hundred Hz and doesn't seem to be precisely tuneable. Just do 110000 +/- 500 since it's not very critical it seems. */ - if (abs(if_set - 109500) <= 500) + if (abs(if_set - 110000) <= 500) return 0; - return if_set < 109500 ? -1 : 1; + return if_set < 110000 ? -1 : 1; } static int sd_setcmp(int regval) @@ -666,8 +677,6 @@ static void set_sleep(bool sleep) (TUNER_PRESENT | TUNER_POWERED)) return; - tuner_status |= TUNER_AWAKE; - enable_afc(false); /* 2. Calibrate the IF frequency at 110 kHz: */ @@ -702,9 +711,79 @@ static void set_sleep(bool sleep) lv24020lp_write(STEREO_CTRL, FMCS_SET(7) | AUTOSSR); lv24020lp_write(PW_SCTRL, SS_CTRL_SET(3) | SM_CTRL_SET(1) | PW_RAD); + + tuner_status |= TUNER_AWAKE; +} + +static int lp24020lp_tuned(void) +{ + return RSS_FS(lv24020lp_read(RADIO_STAT)) < 0x1f; +} + +static int lv24020lp_debug_info(int setting) +{ + int val = -1; + + if (setting >= LV24020LP_DEBUG_FIRST && setting <= LV24020LP_DEBUG_LAST) + { + val = 0; + + if (tuner_awake()) + { + switch (setting) + { + /* tuner-specific debug info */ + case LV24020LP_CTRL_STAT: + val = lv24020lp_read(CTRL_STAT); + break; + + case LV24020LP_REG_STAT: + val = lv24020lp_read(RADIO_STAT); + break; + + case LV24020LP_MSS_FM: + val = tuner_measure(MSS_FM, 1, 16); + break; + + case LV24020LP_MSS_IF: + val = tuner_measure(MSS_IF, 1000, 16); + break; + + case LV24020LP_MSS_SD: + val = tuner_measure(MSS_SD, 1000, 16); + break; + + case LV24020LP_IF_SET: + val = if_set; + break; + + case LV24020LP_SD_SET: + val = sd_set; + break; + } + } + } + + return val; } /** Public interfaces **/ +void lv24020lp_init(void) +{ + mutex_init(&tuner_mtx); +} + +void lv24020lp_lock(void) +{ + mutex_lock(&tuner_mtx); +} + +void lv24020lp_unlock(void) +{ + mutex_unlock(&tuner_mtx); +} + +/* This function expects the driver to be locked externally */ void lv24020lp_power(bool status) { static const unsigned char tuner_defaults[][2] = @@ -734,7 +813,7 @@ void lv24020lp_power(bool status) if (status) { - tuner_status |= TUNER_POWERED | TUNER_PRESENCE_CHECKED; + tuner_status |= (TUNER_PRESENCE_CHECKED | TUNER_POWERED); /* if tuner is present, CHIP ID is 0x09 */ if (lv24020lp_read(CHIP_ID) == 0x09) @@ -750,16 +829,16 @@ void lv24020lp_power(bool status) lv24020lp_write(tuner_defaults[i][0], tuner_defaults[i][1]); /* Complete the startup calibration if the tuner is woken */ - udelay(100000); + sleep(HZ/10); } } else { + tuner_status &= ~(TUNER_POWERED | TUNER_AWAKE); + /* Power off */ if (tuner_status & TUNER_PRESENT) lv24020lp_write_and(PW_SCTRL, ~PW_RAD); - - tuner_status &= ~(TUNER_POWERED | TUNER_AWAKE); } } @@ -767,6 +846,8 @@ int lv24020lp_set(int setting, int value) { int val = 1; + mutex_lock(&tuner_mtx); + switch(setting) { case RADIO_SLEEP: @@ -780,7 +861,7 @@ int lv24020lp_set(int setting, int value) case RADIO_SCAN_FREQUENCY: /* TODO: really implement this */ set_frequency(value); - val = lv24020lp_get(RADIO_TUNED); + val = lp24020lp_tuned(); break; case RADIO_MUTE: @@ -791,13 +872,11 @@ int lv24020lp_set(int setting, int value) break; case RADIO_REGION: - { if (lv24020lp_region_data[value]) lv24020lp_write_or(AUDIO_CTRL2, DEEMP); else lv24020lp_write_and(AUDIO_CTRL2, ~DEEMP); break; - } case RADIO_FORCE_MONO: if (value) @@ -807,9 +886,11 @@ int lv24020lp_set(int setting, int value) break; default: - val = -1; + value = -1; } + mutex_unlock(&tuner_mtx); + return val; } @@ -817,11 +898,13 @@ int lv24020lp_get(int setting) { int val = -1; + mutex_lock(&tuner_mtx); + switch(setting) { case RADIO_TUNED: /* TODO: really implement this */ - val = RSS_FS(lv24020lp_read(RADIO_STAT)) < 0x1f; + val = lp24020lp_tuned(); break; case RADIO_STEREO: @@ -833,38 +916,21 @@ int lv24020lp_get(int setting) bool fmstatus = true; if (!(tuner_status & TUNER_PRESENCE_CHECKED)) - fmstatus = tuner_power(true); + fmstatus = tuner_power_nolock(true); val = (tuner_status & TUNER_PRESENT) != 0; if (!fmstatus) - tuner_power(false); + tuner_power_nolock(false); break; } - /* tuner-specific debug info */ - case LV24020LP_CTRL_STAT: - return lv24020lp_read(CTRL_STAT); - - case LV24020LP_REG_STAT: - return lv24020lp_read(RADIO_STAT); - - case LV24020LP_MSS_FM: - return tuner_measure(MSS_FM, 1, 16); - - case LV24020LP_MSS_IF: - return tuner_measure(MSS_IF, 1000, 16); - - case LV24020LP_MSS_SD: - return tuner_measure(MSS_SD, 1000, 16); - - case LV24020LP_IF_SET: - return if_set; - - case LV24020LP_SD_SET: - return sd_set; + default: + val = lv24020lp_debug_info(setting); } + mutex_unlock(&tuner_mtx); + return val; } #endif /* BOOTLOADER */ diff --git a/firmware/export/lv24020lp.h b/firmware/export/lv24020lp.h index 0fc39b18df..7d24435353 100644 --- a/firmware/export/lv24020lp.h +++ b/firmware/export/lv24020lp.h @@ -32,16 +32,17 @@ #define LV24020LP_IF_SET (RADIO_GET_CHIP_FIRST+5) #define LV24020LP_SD_SET (RADIO_GET_CHIP_FIRST+6) -struct lv24020lp_region_data -{ - unsigned char deemphasis; -} __attribute__((packed)); +#define LV24020LP_DEBUG_FIRST LV24020LP_CTRL_STAT +#define LV24020LP_DEBUG_LAST LV24020LP_SD_SET const unsigned char lv24020lp_region_data[TUNER_NUM_REGIONS]; int lv24020lp_set(int setting, int value); int lv24020lp_get(int setting); void lv24020lp_power(bool status); +void lv24020lp_init(void); +void lv24020lp_lock(void); +void lv24020lp_unlock(void); #ifndef CONFIG_TUNER_MULTI #define tuner_set lv24020lp_set diff --git a/firmware/export/power.h b/firmware/export/power.h index 8ecff6c51e..fbc3ded3c1 100644 --- a/firmware/export/power.h +++ b/firmware/export/power.h @@ -49,6 +49,7 @@ bool spdif_powered(void); #if CONFIG_TUNER extern bool tuner_power(bool status); +extern bool tuner_power_nolock(bool status); extern bool tuner_powered(void); #endif diff --git a/firmware/target/arm/sandisk/sansa-e200/power-e200.c b/firmware/target/arm/sandisk/sansa-e200/power-e200.c index 002dcb8407..2745f0ba50 100644 --- a/firmware/target/arm/sandisk/sansa-e200/power-e200.c +++ b/firmware/target/arm/sandisk/sansa-e200/power-e200.c @@ -66,9 +66,11 @@ void ide_power_enable(bool on) /** Tuner **/ static bool powered = false; -bool tuner_power(bool status) +bool tuner_power_nolock(bool status) { - bool old_status = powered; + bool old_status; + + old_status = powered; if (status != old_status) { @@ -115,6 +117,15 @@ bool tuner_power(bool status) return old_status; } +bool tuner_power(bool status) +{ + bool old_status; + lv24020lp_lock(); + old_status = tuner_power_nolock(status); + lv24020lp_unlock(); + return old_status; +} + bool tuner_powered(void) { return powered; diff --git a/firmware/tuner.c b/firmware/tuner.c index 1ee42a5355..4f3ddc0c73 100644 --- a/firmware/tuner.c +++ b/firmware/tuner.c @@ -60,13 +60,15 @@ const struct tea5767_region_data tea5767_region_data[TUNER_NUM_REGIONS] = #ifdef CONFIG_TUNER_MULTI int (*tuner_set)(int setting, int value); int (*tuner_get)(int setting); -#define TUNER_TYPE_CASE(type, set, get, region_data) \ +#define TUNER_TYPE_CASE(type, set, get, ...) \ case type: \ tuner_set = set; \ tuner_get = get; \ + __VA_ARGS__; \ break; #else -#define TUNER_TYPE_CASE(type, set, get, region_data) +#define TUNER_TYPE_CASE(type, set, get, ...) \ + __VA_ARGS__; #endif /* CONFIG_TUNER_MULTI */ void tuner_init(void) @@ -79,19 +81,17 @@ void tuner_init(void) TUNER_TYPE_CASE(LV24020LP, lv24020lp_set, lv24020lp_get, - lv24020lp_region_data) + lv24020lp_init()) #endif #if (CONFIG_TUNER & TEA5767) TUNER_TYPE_CASE(TEA5767, tea5767_set, - tea5767_get, - tea5767_region_data) + tea5767_get) #endif #if (CONFIG_TUNER & S1A0903X01) TUNER_TYPE_CASE(S1A0903X01, s1a0903x01_set, - s1a0903x01_get, - NULL) + s1a0903x01_get) #endif } }