Implement region setting for the fm tuner. The region setting affects deemphasis, band limits and step size. Fixes FS#5929, FS#5928.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11133 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 1c6c0a3..f93ce0a 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -7408,10 +7408,10 @@
   desc: in radio screen
   user:
   <source>
-    *: "Station: %d.%dMHz"
+    *: "Station: %d.%02d MHz"
   </source>
   <dest>
-    *: "Station: %d.%dMHz"
+    *: "Station: %d.%02d MHz"
   </dest>
   <voice>
     *: ""
@@ -7646,10 +7646,10 @@
   desc: during auto scan
   user:
   <source>
-    *: "Scanning %d.%01dMHz"
+    *: "Scanning %d.%02d MHz"
   </source>
   <dest>
-    *: "Scanning %d.%01dMHz"
+    *: "Scanning %d.%02d MHz"
   </dest>
   <voice>
     *: ""
@@ -7660,10 +7660,10 @@
   desc: default preset name for auto scan mode
   user:
   <source>
-    *: "%d.%01dMHz"
+    *: "%d.%02d MHz"
   </source>
   <dest>
-    *: "%d.%01dMHz"
+    *: "%d.%02d MHz"
   </dest>
   <voice>
     *: ""
@@ -9862,3 +9862,68 @@
     *: "Disable auto-resume if phones not present"
   </voice>
 </phrase>
+<phrase>
+  id: LANG_FM_REGION
+  desc: fm tuner region setting
+  <source>
+    *: "Region"
+  </source>
+  <dest>
+    *: "Region"
+  </dest>
+  <voice>
+    *: "Region"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_FM_EUROPE
+  desc: fm tuner region europe
+  <source>
+    *: "Europe"
+  </source>
+  <dest>
+    *: "Europe"
+  </dest>
+  <voice>
+    *: "Europe"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_FM_US
+  desc: fm region us / canada
+  <source>
+    *: "US / Canada"
+  </source>
+  <dest>
+    *: "US / Canada"
+  </dest>
+  <voice>
+    *: "US / Canada"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_FM_JAPAN
+  desc: fm region japan
+  <source>
+    *: "Japan"
+  </source>
+  <dest>
+    *: "Japan"
+  </dest>
+  <voice>
+    *: "Japan"
+  </voice>
+</phrase>
+<phrase>
+  id: LANG_FM_KOREA
+  desc: fm region korea
+  <source>
+    *: "Korea"
+  </source>
+  <dest>
+    *: "Korea"
+  </dest>
+  <voice>
+    *: "Korea"
+  </voice>
+</phrase>
diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c
index 4afe0b2..e7a5912 100644
--- a/apps/recorder/radio.c
+++ b/apps/recorder/radio.c
@@ -85,13 +85,31 @@
 #define FM_RECORD
 #endif
 
-#define MAX_FREQ (108000000)
-#define MIN_FREQ (87500000)
-#define FREQ_STEP 100000
-
 #define RADIO_SCAN_MODE 0
 #define RADIO_PRESET_MODE 1
 
+#if (CONFIG_TUNER & TEA5767)
+#define DEEMPH_50 0,
+#define DEEMPH_75 1,
+#define BAND_LIM_EU 0
+#define BAND_LIM_JP 1
+#else
+#define DEEMPH_50
+#define DEEMPH_75
+#define BAND_LIM_EU
+#define BAND_LIM_JP
+#endif
+static struct fm_region_setting fm_region[] = {
+    /* Europe */
+    { LANG_FM_EUROPE, 87500000, 108000000,   50000, DEEMPH_50 BAND_LIM_EU },
+    /* US / Canada */
+    { LANG_FM_US,     87900000, 107900000,  200000, DEEMPH_75 BAND_LIM_EU },
+    /* Japan */
+    { LANG_FM_JAPAN,  76000000,  90000000,  100000, DEEMPH_50 BAND_LIM_JP },
+    /* Korea */
+    { LANG_FM_KOREA,  87500000, 108000000,  100000, DEEMPH_50 BAND_LIM_EU },
+    };
+
 static int curr_preset = -1;
 static int curr_freq;
 static int radio_mode = RADIO_SCAN_MODE;
@@ -194,7 +212,9 @@
     if(radio_status == FMRADIO_OFF)
         radio_power(true);
 
-    curr_freq = global_settings.last_frequency * FREQ_STEP + MIN_FREQ;
+    curr_freq = global_settings.last_frequency 
+        * fm_region[global_settings.fm_region].freq_step 
+        + fm_region[global_settings.fm_region].freq_min;
 
     radio_set(RADIO_SLEEP, 0); /* wake up the tuner */
     radio_set(RADIO_FREQUENCY, curr_freq);
@@ -285,7 +305,7 @@
 {
     int i; 
     int diff;
-    int min_diff = MAX_FREQ;
+    int min_diff = fm_region[global_settings.fm_region].freq_min;
     int preset = -1;
 
     for(i = 0;i < MAX_PRESETS;i++)
@@ -307,7 +327,9 @@
 
 static void remember_frequency(void)
 {
-    global_settings.last_frequency = (curr_freq - MIN_FREQ) / FREQ_STEP;
+    global_settings.last_frequency = (curr_freq 
+        - fm_region[global_settings.fm_region].freq_min) 
+        / fm_region[global_settings.fm_region].freq_step;
     settings_save();
 }
 
@@ -450,11 +472,12 @@
     {
         if(search_dir)
         {
-            curr_freq += search_dir * FREQ_STEP;
-            if(curr_freq < MIN_FREQ)
-                curr_freq = MAX_FREQ;
-            if(curr_freq > MAX_FREQ)
-                curr_freq = MIN_FREQ;
+            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;
 
             /* Tune in and delay */
             radio_set(RADIO_FREQUENCY, curr_freq);
@@ -573,9 +596,11 @@
             case ACTION_STD_PREV:
                 if(radio_mode == RADIO_SCAN_MODE)
                 {
-                     curr_freq -= FREQ_STEP;
-                     if(curr_freq < MIN_FREQ)
-                          curr_freq = MAX_FREQ;
+                     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();
@@ -589,9 +614,11 @@
             case ACTION_STD_NEXT:
                 if(radio_mode == RADIO_SCAN_MODE)
                 {
-                     curr_freq += FREQ_STEP;
-                     if(curr_freq > MAX_FREQ)
-                           curr_freq = MIN_FREQ;
+                     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();
@@ -821,8 +848,8 @@
                 FOR_NB_SCREENS(i)
                     screens[i].puts_scroll(0, top_of_screen, buf);
                 
-                freq = curr_freq / 100000;
-                snprintf(buf, 128, str(LANG_FM_STATION), freq / 10, freq % 10);
+                freq = curr_freq / 10000;
+                snprintf(buf, 128, str(LANG_FM_STATION), freq / 100, freq % 100);
                 FOR_NB_SCREENS(i)
                     screens[i].puts_scroll(0, top_of_screen + 1, buf);
                 
@@ -1316,6 +1343,39 @@
     return false;
 }
 
+char region_menu_string[32];
+static void create_region_menu(void)
+{
+    snprintf(region_menu_string, sizeof(region_menu_string),
+    "%s: %s", str(LANG_FM_REGION),
+        str(fm_region[global_settings.fm_region].lang));
+}
+
+static bool toggle_region_mode(void)
+{
+    global_settings.fm_region++;
+    if(global_settings.fm_region >= 
+        (int)(sizeof(fm_region) / sizeof(struct fm_region_setting)))
+        global_settings.fm_region = 0;
+#if (CONFIG_TUNER & TEA5767)
+    radio_set(RADIO_SET_DEEMPHASIS, 
+        fm_region[global_settings.fm_region].deemphasis);
+    radio_set(RADIO_SET_BAND, fm_region[global_settings.fm_region].band);
+#endif
+    /* make sure the current frequency is in the region range */
+    curr_freq -= (curr_freq - fm_region[global_settings.fm_region].freq_min)
+        % 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_min;
+    if(curr_freq > fm_region[global_settings.fm_region].freq_max)
+        curr_freq = fm_region[global_settings.fm_region].freq_max;
+    radio_set(RADIO_FREQUENCY, curr_freq);
+
+    settings_save();
+    create_region_menu();
+    return false;
+}
+
 #ifndef FM_MODE
 char radiomode_menu_string[32];
 
@@ -1346,17 +1406,17 @@
         
     if(do_scan)
     {
-        curr_freq = MIN_FREQ;
+        curr_freq = fm_region[global_settings.fm_region].freq_min;
         num_presets = 0;
         memset(presets, 0, sizeof(presets));
-        while(curr_freq <= MAX_FREQ)
+        while(curr_freq <= fm_region[global_settings.fm_region].freq_max)
         {
             if (num_presets >= MAX_PRESETS)
                 break;
 
-            freq = curr_freq /100000;
+            freq = curr_freq / 10000;
             snprintf(buf, MAX_FMPRESET_LEN, str(LANG_FM_SCANNING), 
-                            freq/10, freq % 10);
+                            freq/100, freq % 100);
             gui_syncsplash(0, true, buf);
 
             /* Tune in and delay */
@@ -1373,13 +1433,13 @@
             /* add preset */
             if(tuned){
                  snprintf(buf, MAX_FMPRESET_LEN, 
-                    str(LANG_FM_DEFAULT_PRESET_NAME),freq/10, freq % 10);
+                    str(LANG_FM_DEFAULT_PRESET_NAME),freq/100, freq % 100);
                  strcpy(presets[num_presets].name,buf);
                  presets[num_presets].frequency = curr_freq;
                  num_presets++;
             }
 
-            curr_freq += FREQ_STEP;
+            curr_freq += fm_region[global_settings.fm_region].freq_step;
                    
         }
 
@@ -1504,6 +1564,7 @@
 #ifndef FM_MODE
         { radiomode_menu_string          , toggle_radio_mode     },
 #endif
+        { region_menu_string             , toggle_region_mode    },
         { ID2P(LANG_SOUND_SETTINGS)      , sound_menu            },
 #ifndef SIMULATOR
 #if defined(HAVE_FMRADIO_IN) || CONFIG_CODEC != SWCODEC
@@ -1515,6 +1576,7 @@
     };
 
     create_monomode_menu();
+    create_region_menu();
 #ifndef FM_MODE
     create_radiomode_menu();
 #endif
diff --git a/apps/recorder/radio.h b/apps/recorder/radio.h
index fdf446d..439061e 100644
--- a/apps/recorder/radio.h
+++ b/apps/recorder/radio.h
@@ -42,6 +42,18 @@
     char name[MAX_FMPRESET_LEN+1];
 };
 
+struct fm_region_setting
+{
+    int lang;
+    int freq_min;
+    int freq_max;
+    int freq_step;
+#if (CONFIG_TUNER & TEA5767)
+    int deemphasis; /* 0: 50us, 1: 75us */
+    int band; /* 0: europe, 1: japan (BL in TEA spec)*/
+#endif
+};
+
 #endif
 
 #endif
diff --git a/apps/settings.c b/apps/settings.c
index d419d4a..ebe0d1e 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -661,6 +661,9 @@
     {4, S_O(unplug_rw), 0, "rewind duration on pause", NULL},
     {1, S_O(unplug_autoresume), 0, "disable autoresume if phones not present", off_on },
 #endif
+#ifdef CONFIG_TUNER
+    {2, S_O(fm_region), 0, "fm_region", "eu,us,jp,kr" },
+#endif
 
     /* If values are just added to the end, no need to bump the version. */
     /* new stuff to be added at the end */
diff --git a/apps/settings.h b/apps/settings.h
index 09834ec..b29a219 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -491,6 +491,10 @@
     int unplug_rw; /* time in s to rewind when pausing */
     bool unplug_autoresume; /* disable auto-resume if no phones */
 #endif
+#ifdef CONFIG_TUNER
+    int fm_region;
+#endif
+
 };
 
 enum optiontype { INT, BOOL };
diff --git a/firmware/export/tuner.h b/firmware/export/tuner.h
index a6a7e8e..48d9bc9 100644
--- a/firmware/export/tuner.h
+++ b/firmware/export/tuner.h
@@ -27,6 +27,10 @@
 #define RADIO_IF_MEASUREMENT 3
 #define RADIO_SENSITIVITY 4
 #define RADIO_FORCE_MONO 5
+#if (CONFIG_TUNER & TEA5767)
+#define RADIO_SET_DEEMPHASIS 6
+#define RADIO_SET_BAND 7
+#endif
 /* readback from the tuner layer */
 #define RADIO_PRESENT 0
 #define RADIO_TUNED 1
diff --git a/firmware/tuner_philips.c b/firmware/tuner_philips.c
index 2958e9e..89c7dd1 100644
--- a/firmware/tuner_philips.c
+++ b/firmware/tuner_philips.c
@@ -73,6 +73,14 @@
             fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes));
             break;
 
+        case RADIO_SET_DEEMPHASIS:
+            write_bytes[4] = (write_bytes[4] & ~(1<<6)) | (value ? (1<<6) : 0);
+            fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes));
+            break;
+
+        case RADIO_SET_BAND:
+            write_bytes[3] = (write_bytes[3] & ~(1<<5)) | (value ? (1<<5) : 0);
+            fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes));
         default:
             return;
     }