Index: apps/recorder/radio.c
===================================================================
--- apps/recorder/radio.c	(revision 12782)
+++ apps/recorder/radio.c	(working copy)
@@ -224,8 +224,10 @@
 
     if(radio_status == FMRADIO_OFF)
     {
+#if (CONFIG_TUNER & S1A0903X01)
         radio_set(RADIO_IF_MEASUREMENT, 0);
         radio_set(RADIO_SENSITIVITY, 0);
+#endif
         radio_set(RADIO_FORCE_MONO, global_settings.fm_force_mono);
 #if (CONFIG_TUNER & TEA5767)
         radio_set(RADIO_SET_DEEMPHASIS, 
@@ -365,41 +367,84 @@
     remember_frequency();
 }
 
+static int step_freq(int f, int direction)
+{
+    f += direction*fm_region[global_settings.fm_region].freq_step;
 
+    if (direction > 0)
+    {
+        if (f > fm_region[global_settings.fm_region].freq_max)
+            f = fm_region[global_settings.fm_region].freq_min;
+    }
+    else if (direction < 0)
+    {
+        if (f < fm_region[global_settings.fm_region].freq_min)
+            f = fm_region[global_settings.fm_region].freq_max;
+    }
+
+    return f;
+}
+
+static void next_station(int direction)
+{
+    if (direction != 0 && radio_mode != RADIO_SCAN_MODE)
+    {
+        next_preset(direction);
+        return;
+    }
+
+    curr_freq = step_freq(curr_freq, direction);
+    if (radio_status == FMRADIO_PLAYING)
+        radio_set(RADIO_MUTE, 1);
+    radio_set(RADIO_FREQUENCY, curr_freq);
+    if (radio_status == FMRADIO_PLAYING)
+        radio_set(RADIO_MUTE, 0);
+    curr_preset = find_preset(curr_freq);
+    remember_frequency();
+}
+
 int radio_screen(void)
 {
     char buf[MAX_PATH];
     bool done = false;
-    int button, lastbutton = BUTTON_NONE;
     int ret_val = GO_TO_ROOT;
-#ifdef FM_RECORD_DBLPRE
-    unsigned long rec_lastclick = 0;
-#endif
-    int freq, i;
-    bool tuned;
-    bool stereo = false;
+    int button;
+    int i;
     int search_dir = 0;
+    bool stereo = false, last_stereo = false;
     int fh;
-    bool last_stereo_status = false;
     int top_of_screen = 0;
     bool update_screen = true;
-    int timeout = current_tick + HZ/10;
     bool screen_freeze = false;
+    bool keep_playing = false;
+    bool statusbar = global_settings.statusbar;
+#ifdef FM_RECORD_DBLPRE
+    int lastbutton = BUTTON_NONE;
+    unsigned long rec_lastclick = 0;
+#endif
+#if CONFIG_CODEC != SWCODEC
     bool have_recorded = false;
+    int timeout = current_tick + HZ/10;
     unsigned int seconds = 0;
     unsigned int last_seconds = 0;
-#if CONFIG_CODEC != SWCODEC
     int hours, minutes;
     struct audio_recording_options rec_options;
-#endif
-    bool keep_playing = false;
-    bool statusbar = global_settings.statusbar;
+#endif /* CONFIG_CODEC != SWCODEC */
     int button_timeout = current_tick + (2*HZ);
 #ifdef HAS_BUTTONBAR
     struct gui_buttonbar buttonbar;
     gui_buttonbar_init(&buttonbar);
     gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
 #endif
+
+    /* Ends an in-progress search - needs access to search_dir */
+    void end_search(void)
+    {
+        if (search_dir != 0 && radio_status == FMRADIO_PLAYING)
+            radio_set(RADIO_MUTE, 0);
+        search_dir = 0;
+    }
+
     /* change status to "in screen" */
     in_screen = true;
 
@@ -461,7 +506,6 @@
         radio_start();
 #endif
 
-    /* I hate this thing with vehement passion (jhMikeS): */
    if(num_presets == 0 && yesno_pop(str(LANG_FM_FIRST_AUTOSCAN)))
         scan_presets();
     
@@ -475,49 +519,42 @@
 #endif
 
     cpu_idle_mode(true);
-        
+
     while(!done)
     {
-        if(search_dir)
+        if(search_dir != 0)
         {
-            curr_freq += search_dir 
-                * fm_region[global_settings.fm_region].freq_step;
-            if(curr_freq < fm_region[global_settings.fm_region].freq_min)
-                curr_freq = fm_region[global_settings.fm_region].freq_max;
-            if(curr_freq > fm_region[global_settings.fm_region].freq_max)
-                curr_freq = fm_region[global_settings.fm_region].freq_min;
+            curr_freq = step_freq(curr_freq, search_dir);
+            update_screen = true;
 
-            /* Tune in and delay */
-            radio_set(RADIO_FREQUENCY, curr_freq);
-            sleep(1);
-            
-            /* Start IF measurement */
-            radio_set(RADIO_IF_MEASUREMENT, 1);
-            sleep(1);
+            if(get_action(CONTEXT_FM, HZ/5) != ACTION_NONE)
+            {
+                sleep(HZ/30);
+                goto do_update_screen;
+            }
 
-            /* Now check how close to the IF frequency we are */
-            tuned = radio_get(RADIO_TUNED);
-
-            /* Stop searching if the tuning is close */
-            if(tuned)
+            if(radio_set(RADIO_SCAN_FREQUENCY, curr_freq))
             {
-                search_dir = 0;
                 curr_preset = find_preset(curr_freq);
                 remember_frequency();
+                end_search();
             }
-            
-            update_screen = true;
         }
 
-        if(search_dir)
-            button = button_get(false);
-        else
-            button = get_action(CONTEXT_FM, HZ / PEAK_METER_FPS);
+#if CONFIG_CODEC != SWCODEC
+        button = get_action(CONTEXT_FM,
+            update_screen ? TIMEOUT_NOBLOCK : HZ / PEAK_METER_FPS);
+#else
+        button = get_action(CONTEXT_FM,
+            update_screen ? TIMEOUT_NOBLOCK : HZ);
+#endif
+
         if (button != ACTION_NONE)
         {
             cpu_idle_mode(false);
             button_timeout = current_tick + (2*HZ);
         }
+
         switch(button)
         {
              case ACTION_FM_STOP:
@@ -559,7 +596,7 @@
                     rec_lastclick = current_tick;
                     break;
                 }    
-#endif
+#endif /* FM_RECORD_DBLPRE */
 #ifndef SIMULATOR
                 if(audio_status() == AUDIO_STATUS_RECORD)
                 {
@@ -572,7 +609,7 @@
                     rec_record();
                     update_screen = true;
                 }
-#endif
+#endif /* SIMULATOR */
                 last_seconds = 0;
                 break;
 #endif /* #ifdef FM_RECORD */
@@ -602,64 +639,31 @@
                 break;
 
             case ACTION_STD_PREV:
-                if(radio_mode == RADIO_SCAN_MODE)
-                {
-                     curr_freq 
-                         -= fm_region[global_settings.fm_region].freq_step;
-                     if(curr_freq < fm_region[global_settings.fm_region].freq_min)
-                          curr_freq 
-                          = fm_region[global_settings.fm_region].freq_max;
-                     radio_set(RADIO_FREQUENCY, curr_freq);
-                     curr_preset = find_preset(curr_freq);
-                     remember_frequency();
-                }
-                else
-                     next_preset(-1);
-                search_dir = 0;
-                update_screen = true;
-                break;
-
             case ACTION_STD_NEXT:
-                if(radio_mode == RADIO_SCAN_MODE)
-                {
-                     curr_freq 
-                         += fm_region[global_settings.fm_region].freq_step;
-                     if(curr_freq > fm_region[global_settings.fm_region].freq_max)
-                           curr_freq 
-                            = fm_region[global_settings.fm_region].freq_min;
-                     radio_set(RADIO_FREQUENCY, curr_freq);
-                     curr_preset = find_preset(curr_freq);
-                     remember_frequency();
-                }
-                else
-                     next_preset(1);
-                search_dir = 0;
+                next_station(button == ACTION_STD_PREV ? -1 : 1);
+                end_search();
                 update_screen = true;
                 break;
 
             case ACTION_STD_PREVREPEAT:
-                if(radio_mode == RADIO_SCAN_MODE)
-                    search_dir = -1;
-                else
+            case ACTION_STD_NEXTREPEAT:
+            {
+                int dir = search_dir;
+                search_dir = button == ACTION_STD_PREVREPEAT ? -1 : 1;
+                if (radio_mode != RADIO_SCAN_MODE)
                 {
-                    next_preset(-1);
+                    next_preset(search_dir);
+                    end_search();
                     update_screen = true;
                 }
-
-                break;
-
-            case ACTION_STD_NEXTREPEAT:
-                if(radio_mode == RADIO_SCAN_MODE)
-                    search_dir = 1;
-                else
+                else if (dir == 0)
                 {
-                    next_preset(1);
+                    radio_set(RADIO_MUTE, 1);
                     update_screen = true;
                 }
-                
                 break;
+                }
 
-
             case ACTION_SETTINGS_INC:
             case ACTION_SETTINGS_INCREPEAT:
                 global_settings.volume++;
@@ -734,7 +738,7 @@
 #endif
                 update_screen = true;
                 break;
-#endif
+#endif /* FM_PRESET */
                 
 #ifdef FM_FREEZE
             case ACTION_FM_FREEZE:
@@ -749,10 +753,13 @@
                     screen_freeze = false;
                 }
                 break;
-#endif                
+#endif /* FM_FREEZE */
+
             case SYS_USB_CONNECTED:
+#if CONFIG_CODEC != SWCODEC
                 /* Only accept USB connection when not recording */
                 if(audio_status() != AUDIO_STATUS_RECORD)
+#endif
                 {
                     default_event_handler(SYS_USB_CONNECTED);
                     screen_freeze = true; /* Cosmetic: makes sure the
@@ -773,18 +780,20 @@
                     radio_mode = RADIO_SCAN_MODE;
                 update_screen = true;
                 break;
-#endif
+#endif /* FM_MODE */
+
 #ifdef FM_NEXT_PRESET
             case ACTION_FM_NEXT_PRESET:
                 next_preset(1);
-                search_dir = 0;
+                end_search();
                 update_screen = true;
                 break;
 #endif
+
 #ifdef FM_PREV_PRESET
             case ACTION_FM_PREV_PRESET:
                 next_preset(-1);
-                search_dir = 0;
+                end_search();
                 update_screen = true;
                 break;
 #endif
@@ -794,8 +803,10 @@
                 break;
         } /*switch(button)*/
 
+#ifdef FM_RECORD_DBLPRE
         if (button != ACTION_NONE)
             lastbutton = button;
+#endif
 
 #if CONFIG_CODEC != SWCODEC
         peak_meter_peek();
@@ -804,10 +815,9 @@
         if(!screen_freeze)
         {           
             /* Only display the peak meter when not recording */
+#if CONFIG_CODEC != SWCODEC
             if(!audio_status())
             {
-
-#if CONFIG_CODEC != SWCODEC
                 FOR_NB_SCREENS(i)
                 {
                     peak_meter_screen(&screens[i],0,
@@ -815,35 +825,40 @@
                     screens[i].update_rect(0, STATUSBAR_HEIGHT + fh*(top_of_screen + 4),
                                                screens[i].width, fh);
                 }
-#endif
-
             }
 
             if(TIME_AFTER(current_tick, timeout))
             {
                 timeout = current_tick + HZ;
+#else  /* SWCODEC */
+            {
+#endif /* CONFIG_CODEC == SWCODEC */
 
                 /* keep "mono" from always being displayed when paused */
                 if (radio_status != FMRADIO_PAUSED)
                 {
                     stereo = radio_get(RADIO_STEREO) &&
                         !global_settings.fm_force_mono;
-                    if(stereo != last_stereo_status)
+
+                    if(stereo != last_stereo)
                     {
                         update_screen = true;
-                        last_stereo_status = stereo;
+                        last_stereo = stereo;
                     }
                 }
             }
-            
-#ifndef SIMULATOR
-#if CONFIG_CODEC != SWCODEC
+
+do_update_screen:
+#if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
             seconds = audio_recorded_time() / HZ;
-#endif
-#endif
-            if(update_screen || seconds > last_seconds)
+            if (update_screen || seconds > last_seconds)
             {
                 last_seconds = seconds;
+#else
+            if (update_screen)
+            {
+#endif
+                int freq;
 
                 FOR_NB_SCREENS(i)
                     screens[i].setfont(FONT_UI);
@@ -871,6 +886,7 @@
                                       str(LANG_RADIO_SCAN_MODE));
                 FOR_NB_SCREENS(i)
                     screens[i].puts_scroll(0, top_of_screen + 3, buf);
+
 #if CONFIG_CODEC != SWCODEC
                 if(audio_status() == AUDIO_STATUS_RECORD)
                 {
@@ -892,7 +908,7 @@
                             screens[i].puts_scroll(0, top_of_screen + 4, buf);
                     }
                 }
-#endif
+#endif /* CONFIG_CODEC != SWCODEC */
 
 #ifdef HAS_BUTTONBAR
                 gui_buttonbar_draw(&buttonbar);
@@ -902,14 +918,17 @@
             }
             /* Only force the redraw if update_screen is true */
             gui_syncstatusbar_draw(&statusbars,true);
-
-            update_screen = false;
         }
 
+        update_screen = false;
+
+#if CONFIG_CODEC != SWCODEC
         if(audio_status() & AUDIO_STATUS_ERROR)
         {
             done = true;
         }
+#endif
+
         if (TIME_AFTER(current_tick, button_timeout))
         {
             cpu_idle_mode(true);
@@ -917,6 +936,7 @@
     } /*while(!done)*/
 
 #ifndef SIMULATOR
+#if CONFIG_CODEC != SWCODEC
     if(audio_status() & AUDIO_STATUS_ERROR)
     {
         gui_syncsplash(0, true, str(LANG_DISK_FULL));
@@ -933,16 +953,15 @@
         }
     }
     
-#if CONFIG_CODEC != SWCODEC
     audio_init_playback();
-#endif
+#endif /* CONFIG_CODEC != SWCODEC */
 
     sound_settings_apply();
 #endif /* SIMULATOR */
 
     if(keep_playing)
     {
-/* Catch FMRADIO_PLAYING status for the sim. */ 
+/* Catch FMRADIO_PLAYING status for the sim. */
 #ifndef SIMULATOR
 #if CONFIG_CODEC != SWCODEC
         /* Enable the Left and right A/D Converter */
@@ -951,7 +970,8 @@
                                  AUDIO_GAIN_LINEIN);
         mas_codec_writereg(6, 0x4000);
 #endif
-#endif
+        end_search();
+#endif /* SIMULATOR */
     }
     else
     {
@@ -968,8 +988,11 @@
     global_settings.statusbar = statusbar;
 
     in_screen = false;
-    
+#if CONFIG_CODEC != SWCODEC
     return have_recorded;
+#else
+    return false;
+#endif
 } /* radio_screen */
 
 static void radio_save_presets(void)
@@ -1272,7 +1295,7 @@
             case ACTION_STD_OK:
                 curr_preset = gui_synclist_get_sel_pos(&lists);
                 curr_freq = presets[curr_preset].frequency;
-                radio_set(RADIO_FREQUENCY, curr_freq);
+                next_station(0);
                 remember_frequency();
                 result = 1;
                 break;
@@ -1309,7 +1332,7 @@
         curr_freq = fm_region[region].freq_min;
     if(curr_freq > fm_region[region].freq_max)
         curr_freq = fm_region[region].freq_max;
-    radio_set(RADIO_FREQUENCY, curr_freq);
+    next_station(0);
 
     remember_frequency();
 }
@@ -1340,7 +1363,7 @@
 
 static int scan_presets(void)
 {
-    bool tuned = false, do_scan = true;
+    bool do_scan = true;
     char buf[MAX_FMPRESET_LEN];
     int freq, i;
     
@@ -1352,6 +1375,7 @@
         curr_freq = fm_region[global_settings.fm_region].freq_min;
         num_presets = 0;
         memset(presets, 0, sizeof(presets));
+        radio_set(RADIO_MUTE, 1);
         while(curr_freq <= fm_region[global_settings.fm_region].freq_max)
         {
             if (num_presets >= MAX_PRESETS || action_userabort(TIMEOUT_NOBLOCK))
@@ -1362,30 +1386,21 @@
                             freq/100, freq % 100);
             gui_syncsplash(0, true, buf);
 
-            /* Tune in and delay */
-            radio_set(RADIO_FREQUENCY, curr_freq);
-            sleep(1);
-            
-            /* Start IF measurement */
-            radio_set(RADIO_IF_MEASUREMENT, 1);
-            sleep(1);
-
-            /* Now check how close to the IF frequency we are */
-            tuned = radio_get(RADIO_TUNED);
-
-            /* add preset */
-            if(tuned){
-                 snprintf(buf, MAX_FMPRESET_LEN, 
+            if (radio_set(RADIO_SCAN_FREQUENCY, curr_freq)) {
+                /* add preset */
+                snprintf(buf, MAX_FMPRESET_LEN, 
                     str(LANG_FM_DEFAULT_PRESET_NAME),freq/100, freq % 100);
-                 strcpy(presets[num_presets].name,buf);
-                 presets[num_presets].frequency = curr_freq;
-                 num_presets++;
+                strcpy(presets[num_presets].name,buf);
+                presets[num_presets].frequency = curr_freq;
+                num_presets++;
             }
 
             curr_freq += fm_region[global_settings.fm_region].freq_step;
-                   
         }
 
+        if (radio_status == FMRADIO_PLAYING)
+            radio_set(RADIO_MUTE, 0);
+
         presets_changed = true;
         
         FOR_NB_SCREENS(i)
@@ -1398,13 +1413,15 @@
         if(num_presets > 0 )
         {
             curr_freq = presets[0].frequency;
-            radio_set(RADIO_FREQUENCY, curr_freq);
-            remember_frequency();
             radio_mode = RADIO_PRESET_MODE;
             presets_loaded = true;
+            next_station(0);
         }
         else
+        {
+            next_station(1); /* Wrap it to beginning */
             presets_loaded = false;
+        }
     }
     return true;
 }
Index: apps/debug_menu.c
===================================================================
--- apps/debug_menu.c	(revision 12782)
+++ apps/debug_menu.c	(working copy)
@@ -2074,7 +2074,6 @@
     while(1)
     {
         int row = 0;
-        unsigned long regs;
 
         lcd_clear_display();
         fm_detected = radio_hardware_present();
@@ -2083,16 +2082,31 @@
         lcd_puts(0, row++, buf);
 
 #if (CONFIG_TUNER & S1A0903X01)
-        regs = samsung_get(RADIO_ALL);
-        snprintf(buf, sizeof buf, "Samsung regs: %08lx", regs);
+        snprintf(buf, sizeof buf, "Samsung regs: %08X",
+                 samsung_get(RADIO_ALL));
         lcd_puts(0, row++, buf);
 #endif
 #if (CONFIG_TUNER & TEA5767)
-        regs = philips_get(RADIO_ALL);
-        snprintf(buf, sizeof buf, "Philips regs: %08lx", regs);
-        lcd_puts(0, row++, buf);
+        {
+            struct philips_dbg_info info;
+            philips_dbg_info(&info);
+
+            snprintf(buf, sizeof buf, "Philips regs:");
+            lcd_puts(0, row++, buf);
+
+            snprintf(buf, sizeof buf, "   Read: %02X %02X %02X %02X %02X",
+                (unsigned)info.read_regs[0], (unsigned)info.read_regs[1],
+                (unsigned)info.read_regs[2], (unsigned)info.read_regs[3],
+                (unsigned)info.read_regs[4]);
+            lcd_puts(0, row++, buf);
+
+            snprintf(buf, sizeof buf, "   Write: %02X %02X %02X %02X %02X",
+                (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]);
+            lcd_puts(0, row++, buf);
+        }
 #endif
-
         lcd_update();
 
         if (action_userabort(HZ))
Index: firmware/export/tuner.h
===================================================================
--- firmware/export/tuner.h	(revision 12782)
+++ firmware/export/tuner.h	(working copy)
@@ -27,26 +27,32 @@
 #define RADIO_IF_MEASUREMENT 3
 #define RADIO_SENSITIVITY 4
 #define RADIO_FORCE_MONO 5
+#define RADIO_SCAN_FREQUENCY 6
 #if (CONFIG_TUNER & TEA5767)
-#define RADIO_SET_DEEMPHASIS 6
-#define RADIO_SET_BAND 7
+#define RADIO_SET_DEEMPHASIS 7
+#define RADIO_SET_BAND 8
 #endif
 /* readback from the tuner layer */
 #define RADIO_PRESENT 0
 #define RADIO_TUNED 1
 #define RADIO_STEREO 2
-#define RADIO_ALL 3 /* debug */
 
 #if CONFIG_TUNER
 
 #if (CONFIG_TUNER & S1A0903X01)
-void samsung_set(int setting, int value);
+int samsung_set(int setting, int value);
 int samsung_get(int setting);
 #endif
 
 #if (CONFIG_TUNER & TEA5767)
-void philips_set(int setting, int value);
+struct philips_dbg_info
+{
+    unsigned char read_regs[5];
+    unsigned char write_regs[5];
+};
+int philips_set(int setting, int value);
 int philips_get(int setting);
+void philips_dbg_info(struct philips_dbg_info *info);
 #endif
 
 #endif /* #if CONFIG_TUNER */
Index: firmware/tuner_philips.c
===================================================================
--- firmware/tuner_philips.c	(revision 12782)
+++ firmware/tuner_philips.c	(working copy)
@@ -24,60 +24,243 @@
 #include "kernel.h"
 #include "tuner.h" /* tuner abstraction interface */
 #include "fmradio_i2c.h" /* physical interface driver */
+#include "logf.h"
 
-#define I2C_ADR 0xC0
+#define B1                  0
+#define B2                  1
+#define B3                  2
+#define B4                  3
+#define B5                  4
+
+/* Write bytes */
+#define B1_WR_MUTE          (1 << 7)
+#define B1_WR_SM            (1 << 6)
+#define B1_WR_PLLMASK       0x3f
+#define B1_WR_PLL(pllw)     (((unsigned)(pllw) >> 8) & B1_WR_PLLMASK)
+
+#define B2_WR_PLL(pllw)     ((unsigned char)(pllw))
+
+#define B3_WR_SUD           (1 << 7)
+#define B3_WR_SSL_LOW       0x01
+#define B3_WR_SSL_MID       0x02
+#define B3_WR_SSL_HIGH      0x03
+#define B3_WR_SSL(x)        (((x) & 0x03) << 5)
+#define B3_WR_HLSI          (1 << 4)
+#define B3_WR_MS            (1 << 3)
+#define B3_WR_MR            (1 << 2)
+#define B3_WR_ML            (1 << 1)
+#define B3_WR_SWP1          (1 << 0)
+
+#define B4_WR_SWP2          (1 << 7)
+#define B4_WR_STBY          (1 << 6)
+#define B4_WR_BL            (1 << 5)
+#define B4_WR_XTAL          (1 << 4)
+#define B4_WR_SMUTE         (1 << 3)
+#define B4_WR_HCC           (1 << 2)
+#define B4_WR_SNC           (1 << 1)
+#define B4_WR_SI            (1 << 0)
+
+#define B5_WR_PLLREF        (1 << 7)
+#define B5_WR_DTC           (1 << 6)
+/* B5 bits 5:0 - position is don't care */
+
+/* Read bytes */
+#define B1_RD_RF            (1 << 7)
+#define B1_RD_BLF           (1 << 6)
+#define B1_RD_PLL(rb)       (((rb)[B2] & 0x3f) << 8)
+
+#define B2_RD_PLL(rb)       ((unsigned char)(rb)[B2])
+
+#define B3_RD_STEREO        (1 << 7)
+#define B3_RD_IFC(rb)       ((rb)[B3] & 0x7f)
+
+#define B4_RD_LEV(rb)       ((rb)[B4] >> 4)
+#define B4_RD_CID(rb)       (((rb)[B4] & 0x0e) >> 1)
+
+/* B5 read unused */
+
+
+#define I2C_ADR         0xC0
 static unsigned char write_bytes[5] = { 0x00, 0x00, 0x00, 0x00, 0x00 };
+#define MIN_ADC_LEVEL   5
+#define MAX_LEVEL_DIFF  2
+#define MIN_IFC         0x31
+#define MAX_IFC         0x3e
+#define TEST_DELTA      225000 /* 450000 */
 
+#ifdef HAVE_LCD_COLOR
+#define TUNING_DELAY sleep(HZ/30)
+#else
+#define TUNING_DELAY sleep(HZ/25)
+#endif
+
+struct station_info
+{
+    int tuned;
+    int ifc;
+    int level;
+};
+
+static void set_pll_write(int value)
+{
+    value += (write_bytes[B3] & B3_WR_HLSI) ? 225000 : -225000;
+
+#if CONFIG_TUNER_XTAL == 32768
+    value = (value + 4096) >> 13;
+#else
+    value = (value + 6250) / 12500;
+#endif
+
+    write_bytes[B1] = (write_bytes[B1] & ~B1_WR_PLLMASK) | B1_WR_PLL(value);
+    write_bytes[B2] = B2_WR_PLL(value);
+}
+
+static int write_regs(void)
+{
+    return fmradio_i2c_write(I2C_ADR, write_bytes, 5);
+}
+
+static int read_regs(unsigned char read_bytes[5])
+{
+    return fmradio_i2c_read(I2C_ADR, read_bytes, 5);    
+}
+
+static void read_station_info(struct station_info *si_p)
+{
+    unsigned char read_bytes[5];
+    read_regs(read_bytes);
+    si_p->tuned = B1_RD_RF & read_bytes[B1];
+    si_p->ifc   = B3_RD_IFC(read_bytes);
+    si_p->level = B4_RD_LEV(read_bytes);
+}
+
+static void tune_frequency(int value)
+{
+    struct station_info si[2];
+    int i;
+
+    write_bytes[B3] |= B3_WR_HLSI;
+    value += TEST_DELTA;
+
+    for (i = 0; i < 2; i++)
+    {
+        set_pll_write(value);
+
+        write_regs();
+        TUNING_DELAY;
+
+        read_station_info(&si[i]);
+        value -= 2*TEST_DELTA;
+    }
+
+    if (si[0].level >= si[1].level)
+        write_bytes[B3] ^= B3_WR_HLSI;
+
+    set_pll_write(value + 3*TEST_DELTA);
+
+    write_regs();
+    TUNING_DELAY;
+}
+
+static int scan_frequency(int value)
+{
+    struct station_info si[2];
+    int ok;
+
+    tune_frequency(value);
+    read_station_info(&si[0]);
+
+    ok = si[0].tuned && si[0].level >= MIN_ADC_LEVEL;
+
+    if (ok != 0)
+    {
+        write_bytes[B3] ^= B3_WR_HLSI;
+        set_pll_write(value);
+        write_regs();
+        TUNING_DELAY;
+        read_station_info(&si[1]);
+
+        ok = abs(si[0].level - si[1].level) < MAX_LEVEL_DIFF &&
+             si[1].ifc > MIN_IFC && si[1].ifc < MAX_IFC;
+
+        if (ok != 0)
+        {
+            write_bytes[B3] ^= B3_WR_HLSI;
+            set_pll_write(value);
+            write_regs();
+            TUNING_DELAY;
+        }
+
+        logf("%03d.%02d: %02d %02d %02X %02X %s",
+             value / 1000000,
+             value / 10000 % 100,
+             si[0].level,
+             si[1].level,
+             si[0].ifc,
+             si[1].ifc,
+             ok ? "*" : "");
+    }
+
+    return ok;
+}
+
 /* tuner abstraction layer: set something to the tuner */
-void philips_set(int setting, int value)
+int philips_set(int setting, int value)
 {
     switch(setting)
     {
         case RADIO_SLEEP:
             /* init values */
-            write_bytes[0] |= (1<<7); /* mute */
+            write_bytes[B1] |= B1_WR_MUTE; /* mute */
 #if CONFIG_TUNER_XTAL == 32768
             /* 32.768kHz, soft mute, stereo noise cancelling */
-            write_bytes[3] |= (1<<4) | (1<<3) | (1<<1);
+            write_bytes[B4] |= B4_WR_XTAL | B4_WR_SMUTE | B4_WR_SNC;
 #else
             /* soft mute, stereo noise cancelling */
-            write_bytes[3] |= (1<<3) | (1<<1); 
+            write_bytes[B4] |= B4_WR_SMUTE | B4_WR_SNC; 
 #endif
             /* sleep / standby mode */
-            write_bytes[3] &= ~(1<<6) | (value ? (1<<6) : 0);
+            write_bytes[B4] &= ~B4_WR_STBY;
+            if (value)
+                write_bytes[B4] |= B4_WR_STBY;
             break;
 
         case RADIO_FREQUENCY:
-            {
-                int n;
-#if CONFIG_TUNER_XTAL == 32768
-                n = (4 * (value - 225000) + 16384) / 32768;
-#else
-                n = (4 * (value - 225000)) / 50000;
-#endif
-                write_bytes[0] = (write_bytes[0] & 0xC0) | (n >> 8);
-                write_bytes[1] = n & 0xFF;
-            }
-            break;
+            tune_frequency(value);
+            return 1;
 
+        case RADIO_SCAN_FREQUENCY:
+            return scan_frequency(value);
+
         case RADIO_MUTE:
-            write_bytes[0] = (write_bytes[0] & 0x7F) | (value ? 0x80 : 0);
+            write_bytes[B1] &= ~B1_WR_MUTE;
+            if (value)
+                write_bytes[B1] |= B1_WR_MUTE;
             break;
 
         case RADIO_FORCE_MONO:
-            write_bytes[2] = (write_bytes[2] & 0xF7) | (value ? 0x08 : 0);
+            write_bytes[B3] &= ~B3_WR_MS;
+            if (value)
+                write_bytes[B3] |= B3_WR_MS;
             break;
 
         case RADIO_SET_DEEMPHASIS:
-            write_bytes[4] = (write_bytes[4] & ~(1<<6)) | (value ? (1<<6) : 0);
+            write_bytes[B5] &= ~B5_WR_DTC;
+            if (value)
+                write_bytes[B5] |= B5_WR_DTC;
             break;
 
         case RADIO_SET_BAND:
-            write_bytes[3] = (write_bytes[3] & ~(1<<5)) | (value ? (1<<5) : 0);
+            write_bytes[B4] &= ~B4_WR_BL;
+            if (value)
+                write_bytes[B4] |= B4_WR_BL;
+            break;
         default:
-            return;
+            return -1;
     }
-    fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes));
+
+    write_regs();
+    return 1;
 }
 
 /* tuner abstraction layer: read something from the tuner */
@@ -86,7 +269,7 @@
     unsigned char read_bytes[5];
     int val = -1; /* default for unsupported query */
 
-    fmradio_i2c_read(I2C_ADR, read_bytes, sizeof(read_bytes));
+    read_regs(read_bytes);
 
     switch(setting)
     {
@@ -95,24 +278,20 @@
             break;
 
         case RADIO_TUNED:
-            val = 0;
-            if (read_bytes[0] & 0x80) /* ready */
-            {
-                val = read_bytes[2] & 0x7F; /* IF counter */
-                val = (abs(val - 0x36) < 2); /* close match */
-            }
+            val = (read_bytes[B1] & B1_RD_RF) &&
+                  B4_RD_LEV(read_bytes) >= MIN_ADC_LEVEL;
             break;
 
         case RADIO_STEREO:
-            val = read_bytes[2] >> 7;
+            val = read_bytes[B3] & B3_RD_STEREO;
             break;
+    }
 
-        case RADIO_ALL: /* debug query */
-            val = read_bytes[0] << 24 
-                | read_bytes[1] << 16 
-                | read_bytes[2] << 8 
-                | read_bytes[3];
-            break;
-    }
     return val;
 }
+
+void philips_dbg_info(struct philips_dbg_info *info)
+{
+    read_regs(info->read_regs);
+    memcpy(info->write_regs, write_bytes, 5);
+}
Index: firmware/tuner_samsung.c
===================================================================
--- firmware/tuner_samsung.c	(revision 12782)
+++ firmware/tuner_samsung.c	(working copy)
@@ -34,8 +34,10 @@
 static int fm_in2;
 
 /* tuner abstraction layer: set something to the tuner */
-void samsung_set(int setting, int value)
+int samsung_set(int setting, int value)
 {
+    int val = 1;
+
     switch(setting)
     {
         case RADIO_SLEEP:
@@ -90,6 +92,16 @@
             break;
         }
 
+        case RADIO_SCAN_FREQUENCY:
+            /* Tune in and delay */
+            samsung_set(RADIO_FREQUENCY, value);
+            sleep(1);
+            /* Start IF measurement */
+            samsung_set(RADIO_IF_MEASUREMENT, 1);
+            sleep(1);
+            val = samsung_get(RADIO_TUNED);
+            break;
+
         case RADIO_MUTE:
             fm_in1 = (fm_in1 & 0xfffffffe) | (value?1:0);
             fmradio_set(1, fm_in1);
@@ -109,7 +121,11 @@
             fm_in2 = (fm_in2 & 0xfffffffb) | (value?0:4);
             fmradio_set(2, fm_in2);
             break;
+        default:
+            val = -1;
     }
+
+    return val;
 }
 
 /* tuner abstraction layer: read something from the tuner */
