summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2008-12-27 19:18:50 +0000
committerMichael Sevakis <jethead71@rockbox.org>2008-12-27 19:18:50 +0000
commit1fea6f6b22af74e904d918fff4cebec345529f4b (patch)
tree1cdddb0ab125099b7439fd80984517d4a1880341
parentd6bae6c858413544ff0671910654f709d195e427 (diff)
downloadrockbox-1fea6f6b22af74e904d918fff4cebec345529f4b.tar.gz
rockbox-1fea6f6b22af74e904d918fff4cebec345529f4b.zip
Make si4700 tuner driver more sane with bit and field defines and entirely hide strange i2c interface from code with write/set/clear/masked functionality. On Gigabeat S use by-the-book busmode selection and GPIO lines. Implement some primitive station detection, debug registers in screen, and misc. changes to tie things together.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19600 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/debug_menu.c28
-rw-r--r--firmware/drivers/tuner/si4700.c418
-rwxr-xr-xfirmware/export/imx31l.h100
-rw-r--r--firmware/export/power.h1
-rw-r--r--firmware/export/si4700.h6
-rw-r--r--firmware/target/arm/as3525/power-as3525.c16
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c75
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/power-imx31.c43
-rw-r--r--firmware/tuner.c2
9 files changed, 513 insertions, 176 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index f390cced85..9be36df046 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -2293,12 +2293,12 @@ static int radio_callback(int btn, struct gui_synclist *lists)
2293 "if_set: %d Hz", lv24020lp_get(LV24020LP_IF_SET) ); 2293 "if_set: %d Hz", lv24020lp_get(LV24020LP_IF_SET) );
2294 simplelist_addline(SIMPLELIST_ADD_LINE, 2294 simplelist_addline(SIMPLELIST_ADD_LINE,
2295 "sd_set: %d Hz", lv24020lp_get(LV24020LP_SD_SET) ); 2295 "sd_set: %d Hz", lv24020lp_get(LV24020LP_SD_SET) );
2296#endif 2296#endif /* LV24020LP */
2297#if (CONFIG_TUNER & S1A0903X01) 2297#if (CONFIG_TUNER & S1A0903X01)
2298 simplelist_addline(SIMPLELIST_ADD_LINE, 2298 simplelist_addline(SIMPLELIST_ADD_LINE,
2299 "Samsung regs: %08X", s1a0903x01_get(RADIO_ALL)); 2299 "Samsung regs: %08X", s1a0903x01_get(RADIO_ALL));
2300 /* This one doesn't return dynamic data atm */ 2300 /* This one doesn't return dynamic data atm */
2301#endif 2301#endif /* S1A0903X01 */
2302#if (CONFIG_TUNER & TEA5767) 2302#if (CONFIG_TUNER & TEA5767)
2303 struct tea5767_dbg_info nfo; 2303 struct tea5767_dbg_info nfo;
2304 tea5767_dbg_info(&nfo); 2304 tea5767_dbg_info(&nfo);
@@ -2313,7 +2313,29 @@ static int radio_callback(int btn, struct gui_synclist *lists)
2313 (unsigned)nfo.write_regs[0], (unsigned)nfo.write_regs[1], 2313 (unsigned)nfo.write_regs[0], (unsigned)nfo.write_regs[1],
2314 (unsigned)nfo.write_regs[2], (unsigned)nfo.write_regs[3], 2314 (unsigned)nfo.write_regs[2], (unsigned)nfo.write_regs[3],
2315 (unsigned)nfo.write_regs[4]); 2315 (unsigned)nfo.write_regs[4]);
2316#endif 2316#endif /* TEA5767 */
2317#if (CONFIG_TUNER & SI4700)
2318 struct si4700_dbg_info nfo;
2319 si4700_dbg_info(&nfo);
2320 simplelist_addline(SIMPLELIST_ADD_LINE, "SI4700 regs:");
2321 /* Registers */
2322 simplelist_addline(SIMPLELIST_ADD_LINE,
2323 " %04X %04X %04X %04X",
2324 (unsigned)nfo.regs[0], (unsigned)nfo.regs[1],
2325 (unsigned)nfo.regs[2], (unsigned)nfo.regs[3]);
2326 simplelist_addline(SIMPLELIST_ADD_LINE,
2327 " %04X %04X %04X %04X",
2328 (unsigned)nfo.regs[4], (unsigned)nfo.regs[5],
2329 (unsigned)nfo.regs[6], (unsigned)nfo.regs[7]);
2330 simplelist_addline(SIMPLELIST_ADD_LINE,
2331 " %04X %04X %04X %04X",
2332 (unsigned)nfo.regs[8], (unsigned)nfo.regs[9],
2333 (unsigned)nfo.regs[10], (unsigned)nfo.regs[11]);
2334 simplelist_addline(SIMPLELIST_ADD_LINE,
2335 " %04X %04X %04X %04X",
2336 (unsigned)nfo.regs[12], (unsigned)nfo.regs[13],
2337 (unsigned)nfo.regs[14], (unsigned)nfo.regs[15]);
2338#endif /* SI4700 */
2317 return ACTION_REDRAW; 2339 return ACTION_REDRAW;
2318} 2340}
2319static bool dbg_fm_radio(void) 2341static bool dbg_fm_radio(void)
diff --git a/firmware/drivers/tuner/si4700.c b/firmware/drivers/tuner/si4700.c
index f68ea5a750..fb8fc49749 100644
--- a/firmware/drivers/tuner/si4700.c
+++ b/firmware/drivers/tuner/si4700.c
@@ -25,12 +25,33 @@
25#include <string.h> 25#include <string.h>
26#include <stdlib.h> 26#include <stdlib.h>
27#include "kernel.h" 27#include "kernel.h"
28#include "power.h"
28#include "tuner.h" /* tuner abstraction interface */ 29#include "tuner.h" /* tuner abstraction interface */
29#include "fmradio.h" 30#include "fmradio.h"
30#include "fmradio_i2c.h" /* physical interface driver */ 31#include "fmradio_i2c.h" /* physical interface driver */
31 32
33/* some models use the internal 32 kHz oscillator which needs special attention
34 during initialisation, power-up and power-down.
35*/
36#if defined(SANSA_CLIP) || defined(SANSA_E200V2) || defined(SANSA_FUZE)
37#define USE_INTERNAL_OSCILLATOR
38#elif defined(TOSHIBA_GIGABEAT_S)
39#define SI4700_GPIO_SETUP (SYSCONFIG1_GPIO1_HI_Z | \
40 SYSCONFIG1_GPIO2_HI_Z | \
41 SYSCONFIG1_GPIO3_MO_ST_I)
42extern int si4700_st(void);
43#endif
44
45#ifndef SI4700_GPIO_SETUP
46#define SI4700_GPIO_SETUP 0
47#endif
48
49#define SEEK_THRESHOLD 0x16
50#define TUNER_VOLUME 0xC
51
32#define I2C_ADR 0x20 52#define I2C_ADR 0x20
33 53
54/** Registers and bits - "x" denotes Si4702/03 only (so they say) **/
34#define DEVICEID 0x0 55#define DEVICEID 0x0
35#define CHIPID 0x1 56#define CHIPID 0x1
36#define POWERCFG 0x2 57#define POWERCFG 0x2
@@ -43,20 +64,154 @@
43#define BOOTCONFIG 0x9 64#define BOOTCONFIG 0x9
44#define STATUSRSSI 0xA 65#define STATUSRSSI 0xA
45#define READCHAN 0xB 66#define READCHAN 0xB
46#define RDSA 0xC 67#define RDSA 0xC /* x */
47#define RDSB 0xD 68#define RDSB 0xD /* x */
48#define RDSC 0xE 69#define RDSC 0xE /* x */
49#define RDSD 0xF 70#define RDSD 0xF /* x */
50 71
51/* some models use the internal 32 kHz oscillator which needs special attention 72/* DEVICEID (0x0) */
52 during initialisation, power-up and power-down. 73#define DEVICEID_PN (0xf << 12)
53*/ 74 /* 0x01 = Si4700/01 */
54#if defined(SANSA_CLIP) || defined(SANSA_E200V2) || defined(SANSA_FUZE) 75 /* 0x01 = Si4702/03 */
55#define USE_INTERNAL_OSCILLATOR 76#define DEVICEID_MFGID (0xfff << 0)
56#endif 77 /* always 0x242 */
78
79/* CHIPID (0x1) */
80
81#if 0 /* Informational */
82/* Si4700/01 */
83#define CHIPID_REV (0x3f << 10)
84#define CHIPID_DEV (0x1 << 9)
85 /* 0 before powerup */
86 /* 0 after powerup = Si4700 */
87 /* 1 after powerup = Si4701 */
88#define CHIPID_FIRMWARE (0xff << 0)
89
90/* Si4702/03 */
91#define CHIPID_REV (0x3f << 10)
92#define CHIPID_DEV (0xf << 6)
93 /* 0000 before PU = Si4702 */
94 /* 0001 after PU = Si4702 */
95 /* 1000 before PU = Si4703 */
96 /* 1001 after PU = Si4703 */
97#define CHIPID_FIRMWARE (0x3f << 0)
98#endif /* 0 */
99
100/* POWERCFG (0x2) */
101#define POWERCFG_DSMUTE (0x1 << 15)
102#define POWERCFG_DMUTE (0x1 << 14)
103#define POWERCFG_MONO (0x1 << 13)
104#define POWERCFG_RDSM (0x1 << 11) /* x */
105#define POWERCFG_SKMODE (0x1 << 10)
106#define POWERCFG_SEEKUP (0x1 << 9)
107#define POWERCFG_SEEK (0x1 << 8)
108#define POWERCFG_DISABLE (0x1 << 6)
109#define POWERCFG_ENABLE (0x1 << 0)
110
111/* CHANNEL (0x3) */
112#define CHANNEL_TUNE (0x1 << 15)
113#define CHANNEL_CHAN (0x3ff << 0)
114 #define CHANNEL_CHANw(x) ((x) & CHANNEL_CHAN)
115
116/* SYSCONFIG1 (0x4) */
117#define SYSCONFIG1_RDSIEN (0x1 << 15) /* x */
118#define SYSCONFIG1_STCIEN (0x1 << 14)
119#define SYSCONFIG1_RDS (0x1 << 12) /* x */
120#define SYSCONFIG1_DE (0x1 << 11)
121#define SYSCONFIG1_AGCD (0x1 << 10)
122#define SYSCONFIG1_BLNDADJ (0x3 << 6)
123 #define SYSCONFIG1_BLNDADJ_31_39_RSSI (0x0 << 6)
124 #define SYSCONFIG1_BLNDADJ_37_55_RSSI (0x1 << 6)
125 #define SYSCONFIG1_BLNDADJ_19_37_RSSI (0x2 << 6)
126 #define SYSCONFIG1_BLNDADJ_25_43_RSSI (0x3 << 6)
127#define SYSCONFIG1_GPIO3 (0x3 << 4)
128 #define SYSCONFIG1_GPIO3_HI_Z (0x0 << 4)
129 #define SYSCONFIG1_GPIO3_MO_ST_I (0x1 << 4)
130 #define SYSCONFIG1_GPIO3_LOW (0x2 << 4)
131 #define SYSCONFIG1_GPIO3_HI (0x3 << 4)
132#define SYSCONFIG1_GPIO2 (0x3 << 2)
133 #define SYSCONFIG1_GPIO2_HI_Z (0x0 << 2)
134 #define SYSCONFIG1_GPIO2_STC_RDS_I (0x1 << 2)
135 #define SYSCONFIG1_GPIO2_LOW (0x2 << 2)
136 #define SYSCONFIG1_GPIO2_HI (0x3 << 2)
137#define SYSCONFIG1_GPIO1 (0x3 << 0)
138 #define SYSCONFIG1_GPIO1_HI_Z (0x0 << 0)
139 #define SYSCONFIG1_GPIO1_LOW (0x2 << 0)
140 #define SYSCONFIG1_GPIO1_HI (0x3 << 0)
141
142/* SYSCONFIG2 (0x5) */
143#define SYSCONFIG2_SEEKTH (0xff << 8)
144 #define SYSCONFIG2_SKEETHw(x) (((x) << 8) & SYSCONFIG2_SEEKTH)
145#define SYSCONFIG2_BAND (0x3 << 6)
146 #define SYSCONFIG2_BANDw(x) (((x) << 6) & SYSCONFIG2_BAND)
147 #define SYSCONFIG2_BANDr(x) (((x) & SYSCONFIG2_BAND) >> 6)
148 #define SYSCONFIG2_BAND_875_1080 (0x0 << 6) /* tenth-megahertz */
149 #define SYSCONFIG2_BAND_760_1080 (0x1 << 6)
150 #define SYSCONFIG2_BAND_760_900 (0x2 << 6)
151#define SYSCONFIG2_SPACE (0x3 << 4)
152 #define SYSCONFIG2_SPACEw(x) (((x) << 4) & SYSCONFIG2_SPACE)
153 #define SYSCONFIG2_SPACEr(x) (((x) & SYSCONFIG2_SPACE) >> 4)
154 #define SYSCONFIG2_SPACE_200KHZ (0x0 << 4)
155 #define SYSCONFIG2_SPACE_100KHZ (0x1 << 4)
156 #define SYSCONFIG2_SPACE_50KHZ (0x2 << 4)
157/* 4700/01 0000=mute,0001=-28dBFS..2dB steps..1111= +0dBFS */
158/* 4702/03: VOLEXT=0: 0000=mute,0001=-28dBFS..2dB steps..1111= +0dBFS */
159/* VOLEXT=1: 0000=mute,0001=-58dBFS..2dB steps..1111=-30dBFS */
160#define SYSCONFIG2_VOLUME (0xf << 0)
161 #define SYSCONFIG2_VOLUMEw(x) ((x) & SYSCONFIG2_VOLUME)
162
163/* SYSCONFIG3 (0x6) */
164#define SYSCONFIG3_SMUTER (0x3 << 14)
165 #define SYSCONFIG3_SMUTER_FASTEST (0x0 << 14)
166 #define SYSCONFIG3_SMUTER_FAST (0x1 << 14)
167 #define SYSCONFIG3_SMUTER_SLOW (0x2 << 14)
168 #define SYSCONFIG3_SMUTER_SLOWEST (0x3 << 14)
169#define SYSCONFIG3_SMUTEA (0x3 << 12)
170 #define SYSCONFIG3_SMUTEA_16DB (0x0 << 12)
171 #define SYSCONFIG3_SMUTEA_14DB (0x1 << 12)
172 #define SYSCONFIG3_SMUTEA_12DB (0x2 << 12)
173 #define SYSCONFIG3_SMUTEA_10DB (0x3 << 12)
174#define SYSCONFIG3_VOLEXT (0x1 << 8) /* x */
175#define SYSCONFIG3_SKSNR (0xf << 4)
176 #define SYSCONFIG3_SKSNRw(x) (((x) << 4) & SYSCONFIG3_SKSNR)
177#define SYSCONFIG3_SKCNT (0xf << 0)
178 #define SYSCONFIG3_SKCNTw(x) (((x) << 0) & SYSCONFIG3_SKCNT)
179
180/* TEST1 (0x7) */
181/* 4700/01: 15=always 0, 13:0 = write with preexisting values! */
182/* 4702/03: 13:0 = write with preexisting values! */
183#define TEST1_XOSCEN (0x1 << 15) /* x */
184#define TEST1_AHIZEN (0x1 << 14)
185
186/* TEST2 (0x8) */
187/* 15:0 = write with preexisting values! */
188
189/* BOOTCONFIG (0x9) */
190/* 15:0 = write with preexisting values! */
191
192/* STATUSRSSI (0xA) */
193#define STATUSRSSI_RDSR (0x1 << 15) /* x */
194#define STATUSRSSI_STC (0x1 << 14)
195#define STATUSRSSI_SFBL (0x1 << 13)
196#define STATUSRSSI_AFCRL (0x1 << 12)
197#define STATUSRSSI_RDSS (0x1 << 11) /* x */
198#define STATUSRSSI_BLERA (0x3 << 9) /* x */
199#define STATUSRSSI_ST (0x1 << 8)
200#define STATUSRSSI_RSSI (0xff << 0)
201 #define STATUSRSSI_RSSIr(x) ((x) & 0xff)
202
203/* READCHAN (0xB) */
204#define READCHAN_BLERB (0x3 << 14) /* x */
205#define READCHAN_BLERC (0x3 << 12) /* x */
206#define READCHAN_BLERD (0x3 << 10) /* x */
207#define READCHAN_READCHAN (0x3ff << 0)
208
209/* RDSA-D (0xC-0xF) */
210/* 4702/03: RDS Block A-D data */
57 211
58static bool tuner_present = false; 212static bool tuner_present = false;
59static unsigned short cache[16]; 213static int curr_frequency = 87500000; /* Current station frequency (HZ) */
214static uint16_t cache[16];
60 215
61/* reads <len> registers from radio at offset 0x0A into cache */ 216/* reads <len> registers from radio at offset 0x0A into cache */
62static void si4700_read(int len) 217static void si4700_read(int len)
@@ -64,7 +219,7 @@ static void si4700_read(int len)
64 int i; 219 int i;
65 unsigned char buf[32]; 220 unsigned char buf[32];
66 unsigned char *ptr = buf; 221 unsigned char *ptr = buf;
67 unsigned short data; 222 uint16_t data;
68 223
69 fmradio_i2c_read(I2C_ADR, buf, len * 2); 224 fmradio_i2c_read(I2C_ADR, buf, len * 2);
70 for (i = 0; i < len; i++) { 225 for (i = 0; i < len; i++) {
@@ -80,8 +235,8 @@ static void si4700_write(int len)
80 int i; 235 int i;
81 unsigned char buf[32]; 236 unsigned char buf[32];
82 unsigned char *ptr = buf; 237 unsigned char *ptr = buf;
83 unsigned short data; 238 uint16_t data;
84 239
85 for (i = 0; i < len; i++) { 240 for (i = 0; i < len; i++) {
86 data = cache[(i + POWERCFG) & 0xF]; 241 data = cache[(i + POWERCFG) & 0xF];
87 *ptr++ = (data >> 8) & 0xFF; 242 *ptr++ = (data >> 8) & 0xFF;
@@ -90,6 +245,43 @@ static void si4700_write(int len)
90 fmradio_i2c_write(I2C_ADR, buf, len * 2); 245 fmradio_i2c_write(I2C_ADR, buf, len * 2);
91} 246}
92 247
248/* Hide silly, wrapped and continuous register reading and make interface
249 * appear sane and normal. This also makes the driver compatible with
250 * using the 3-wire interface. */
251static uint16_t si4700_read_reg(int reg)
252{
253 si4700_read(((reg - STATUSRSSI) & 0xF) + 1);
254 return cache[reg];
255}
256
257static void si4700_write_reg(int reg, uint16_t value)
258{
259 cache[reg] = value;
260 si4700_write(((reg - POWERCFG) & 0xF) + 1);
261}
262
263static void si4700_write_masked(int reg, uint16_t bits, uint16_t mask)
264{
265 si4700_write_reg(reg, (cache[reg] & ~mask) | (bits & mask));
266}
267
268static void si4700_write_set(int reg, uint16_t mask)
269{
270 si4700_write_reg(reg, cache[reg] | mask);
271}
272
273static void si4700_write_clear(int reg, uint16_t mask)
274{
275 si4700_write_reg(reg, cache[reg] & ~mask);
276}
277
278#if (SI4700_GPIO_SETUP & SYSCONFIG1_GPIO3) != SYSCONFIG1_GPIO3_MO_ST_I
279/* Poll i2c for the stereo status */
280static inline int si4700_st(void)
281{
282 return (si4700_read_reg(STATUSRSSI) & STATUSRSSI_ST) >> 8;
283}
284#endif
93 285
94void si4700_init(void) 286void si4700_init(void)
95{ 287{
@@ -105,8 +297,7 @@ void si4700_init(void)
105 297
106#ifdef USE_INTERNAL_OSCILLATOR 298#ifdef USE_INTERNAL_OSCILLATOR
107 /* enable the internal oscillator */ 299 /* enable the internal oscillator */
108 cache[TEST1] |= (1 << 15); /* XOSCEN */ 300 si4700_write_set(TEST1, TEST1_XOSCEN);
109 si4700_write(6);
110 sleep(HZ/2); 301 sleep(HZ/2);
111#endif 302#endif
112 } 303 }
@@ -114,21 +305,102 @@ void si4700_init(void)
114 tuner_power(false); 305 tuner_power(false);
115} 306}
116 307
117static void si4700_tune(void) 308static void si4700_sleep(int snooze)
118{ 309{
119 cache[CHANNEL] |= (1 << 15); /* Set TUNE high to start tuning */ 310 if (snooze)
120 si4700_write(2); 311 {
312 /** power down **/
313 /* ENABLE high, DISABLE high */
314 si4700_write_set(POWERCFG,
315 POWERCFG_DISABLE | POWERCFG_ENABLE);
316 /* Bits self-clear once placed in powerdown. */
317 cache[POWERCFG] &= ~(POWERCFG_DISABLE | POWERCFG_ENABLE);
318 }
319 else
320 {
321 /** power up **/
322 /* ENABLE high, DISABLE low */
323 si4700_write_masked(POWERCFG, POWERCFG_ENABLE,
324 POWERCFG_DISABLE | POWERCFG_ENABLE);
325 sleep(110 * HZ / 1000);
326
327 /* init register cache */
328 si4700_read(16);
329
330#if SI4700_GPIO_SETUP != 0
331 si4700_write_masked(SYSCONFIG1, SI4700_GPIO_SETUP,
332 SYSCONFIG1_GPIO1 | SYSCONFIG1_GPIO2 |
333 SYSCONFIG1_GPIO3);
334#endif
335 /* -6dB volume, seek threshold 12 */
336 si4700_write_masked(SYSCONFIG2,
337 SYSCONFIG2_SKEETHw(SEEK_THRESHOLD) |
338 SYSCONFIG2_VOLUMEw(TUNER_VOLUME),
339 SYSCONFIG2_VOLUME | SYSCONFIG2_SEEKTH);
340 }
341}
342
343static void si4700_set_frequency(int freq)
344{
345 static const unsigned int spacings[3] =
346 {
347 200000, /* SYSCONFIG2_SPACE_200KHZ */
348 100000, /* SYSCONFIG2_SPACE_100KHZ */
349 50000, /* SYSCONFIG2_SPACE_50KHZ */
350 };
351 static const unsigned int bands[3] =
352 {
353 87500000, /* SYSCONFIG2_BAND_875_1080 */
354 76000000, /* SYSCONFIG2_BAND_760_1080 */
355 76000000, /* SYSCONFIG2_BAND_760_900 */
356 };
357
358 /* check BAND and spacings */
359 int space = SYSCONFIG2_SPACEr(cache[SYSCONFIG2]);
360 int band = SYSCONFIG2_BANDr(cache[SYSCONFIG2]);
361 int chan = (freq - bands[band]) / spacings[space];
362
363 curr_frequency = freq;
364
365 si4700_write_reg(CHANNEL, CHANNEL_CHANw(chan) | CHANNEL_TUNE);
121 366
122 do 367 do
123 { 368 {
124 /* tuning should be done within 60 ms according to the datasheet */ 369 /* tuning should be done within 60 ms according to the datasheet */
125 sleep(HZ * 60 / 1000); 370 sleep(HZ * 60 / 1000);
126 si4700_read(2);
127 } 371 }
128 while (!(cache[STATUSRSSI] & (1 << 14))); /* STC high */ 372 while ((si4700_read_reg(STATUSRSSI) & STATUSRSSI_STC) == 0); /* STC high? */
129 373
130 cache[CHANNEL] &= ~(1 << 15); /* Set TUNE low */ 374 si4700_write_clear(CHANNEL, CHANNEL_TUNE); /* Set TUNE low */
131 si4700_write(2); 375}
376
377static int si4700_tuned(void)
378{
379 /* Primitive tuning check: sufficient level and AFC not railed */
380 uint16_t status = si4700_read_reg(STATUSRSSI);
381 if (STATUSRSSI_RSSIr(status) >= SEEK_THRESHOLD &&
382 (status & STATUSRSSI_AFCRL) == 0)
383 return 1;
384
385 return 0;
386}
387
388static void si4700_set_region(int region)
389{
390 const struct si4700_region_data *rd = &si4700_region_data[region];
391 uint16_t bandspacing = SYSCONFIG2_BANDw(rd->band) |
392 SYSCONFIG2_SPACEw(rd->spacing);
393 uint16_t oldbs = cache[SYSCONFIG2] & (SYSCONFIG2_BAND | SYSCONFIG2_SPACE);
394
395 si4700_write_masked(SYSCONFIG1,
396 rd->deemphasis ? SYSCONFIG1_DE : 0,
397 SYSCONFIG1_DE);
398 si4700_write_masked(SYSCONFIG2, bandspacing,
399 SYSCONFIG2_BAND | SYSCONFIG2_SPACE);
400
401 /* Retune if this region change would change the channel number. */
402 if (oldbs != bandspacing)
403 si4700_set_frequency(curr_frequency);
132} 404}
133 405
134/* tuner abstraction layer: set something to the tuner */ 406/* tuner abstraction layer: set something to the tuner */
@@ -137,95 +409,35 @@ int si4700_set(int setting, int value)
137 switch(setting) 409 switch(setting)
138 { 410 {
139 case RADIO_SLEEP: 411 case RADIO_SLEEP:
140 if (value) 412 si4700_sleep(value);
141 { 413 break;
142 /* power down */
143 cache[POWERCFG] = (1 | (1 << 6)); /* ENABLE high, DISABLE high */
144 si4700_write(1);
145 }
146 else
147 {
148 /* power up */
149 cache[POWERCFG] = 1; /* ENABLE high, DISABLE low */
150 si4700_write(1);
151 sleep(110 * HZ / 1000);
152
153 /* update register cache */
154 si4700_read(16);
155
156 /* -6dB volume, keep everything else as default */
157 cache[SYSCONFIG2] = (cache[SYSCONFIG2] & ~0xF) | 0xC;
158 si4700_write(5);
159 }
160 return 1;
161 414
162 case RADIO_FREQUENCY: 415 case RADIO_FREQUENCY:
163 { 416 si4700_set_frequency(value);
164 static const unsigned int spacings[3] = 417 break;
165 {
166 200000, 100000, 50000
167 };
168 unsigned int chan;
169 unsigned int spacing = spacings[(cache[5] >> 4) & 3] ;
170
171 if (cache[SYSCONFIG2] & (3 << 6)) /* check BAND */
172 {
173 chan = (value - 76000000) / spacing;
174 }
175 else
176 {
177 chan = (value - 87500000) / spacing;
178 }
179
180 cache[CHANNEL] = (cache[CHANNEL] & ~0x3FF) | chan;
181 si4700_tune();
182 return 1;
183 }
184 418
185 case RADIO_SCAN_FREQUENCY: 419 case RADIO_SCAN_FREQUENCY:
186 si4700_set(RADIO_FREQUENCY, value); 420 si4700_set_frequency(value);
187 return 1; 421 return si4700_tuned();
188 422
189 case RADIO_MUTE: 423 case RADIO_MUTE:
190 if (value) 424 si4700_write_masked(POWERCFG, value ? 0 : POWERCFG_DMUTE,
191 { 425 POWERCFG_DMUTE);
192 /* mute */
193 cache[POWERCFG] &= ~(1 << 14);
194 }
195 else
196 {
197 /* unmute */
198 cache[POWERCFG] |= (1 << 14);
199 }
200 break; 426 break;
201 427
202 case RADIO_REGION: 428 case RADIO_REGION:
203 { 429 si4700_set_region(value);
204 const struct si4700_region_data *rd =
205 &si4700_region_data[value];
206
207 cache[SYSCONFIG1] = (cache[SYSCONFIG1] & ~(1 << 11)) | (rd->deemphasis << 11);
208 cache[SYSCONFIG2] = (cache[SYSCONFIG2] & ~(3 << 6)) | (rd->band << 6);
209 cache[SYSCONFIG2] = (cache[SYSCONFIG2] & ~(3 << 4)) | (rd->spacing << 4);
210 break; 430 break;
211 }
212 431
213 case RADIO_FORCE_MONO: 432 case RADIO_FORCE_MONO:
214 if (value) 433 si4700_write_masked(POWERCFG, value ? POWERCFG_MONO : 0,
215 { 434 POWERCFG_MONO);
216 cache[POWERCFG] |= (1 << 13);
217 }
218 else
219 {
220 cache[POWERCFG] &= ~(1 << 13);
221 }
222 break; 435 break;
223 436
224 default: 437 default:
225 return -1; 438 return -1;
226 } 439 }
227 440
228 si4700_write(5);
229 return 1; 441 return 1;
230} 442}
231 443
@@ -241,15 +453,25 @@ int si4700_get(int setting)
241 break; 453 break;
242 454
243 case RADIO_TUNED: 455 case RADIO_TUNED:
244 val = 1; 456 val = si4700_tuned();
245 break; 457 break;
246 458
247 case RADIO_STEREO: 459 case RADIO_STEREO:
248 si4700_read(1); 460 val = si4700_st();
249 val = (cache[STATUSRSSI] & (1 << 8)); /* ST high == Stereo */
250 break; 461 break;
251 } 462 }
252 463
253 return val; 464 return val;
254} 465}
255 466
467void si4700_dbg_info(struct si4700_dbg_info *nfo)
468{
469 memset(nfo->regs, 0, sizeof (nfo->regs));
470
471 if (tuner_powered())
472 {
473 si4700_read(16);
474 memcpy(nfo->regs, cache, sizeof (nfo->regs));
475 }
476}
477
diff --git a/firmware/export/imx31l.h b/firmware/export/imx31l.h
index 6780a5a43f..5a964b8e2e 100755
--- a/firmware/export/imx31l.h
+++ b/firmware/export/imx31l.h
@@ -202,26 +202,33 @@
202#define SW_MUX_CTL_GPIO1_0_GPIO1_1_GPIO1_2_GPIO1_3 IOMUXC_(0x14C) 202#define SW_MUX_CTL_GPIO1_0_GPIO1_1_GPIO1_2_GPIO1_3 IOMUXC_(0x14C)
203#define SW_MUX_CTL_CAPTURE_COMPARE_WATCHDOG_RST_PWMO IOMUXC_(0x150) 203#define SW_MUX_CTL_CAPTURE_COMPARE_WATCHDOG_RST_PWMO IOMUXC_(0x150)
204 204
205#define SW_MUX_OUT_EN_GPIO_DR 0x0 205#define SW_MUX_OUT (0x7 << 4)
206#define SW_MUX_OUT_FUNCTIONAL 0x1 206#define SW_MUX_OUT_GPIO_DR (0x0 << 4)
207#define SW_MUX_OUT_ALTERNATE_1 0x2 207#define SW_MUX_OUT_FUNCTIONAL (0x1 << 4)
208#define SW_MUX_OUT_ALTERNATE_2 0x3 208#define SW_MUX_OUT_ALT1 (0x2 << 4)
209#define SW_MUX_OUT_ALTERNATE_3 0x4 209#define SW_MUX_OUT_ALT2 (0x3 << 4)
210#define SW_MUX_OUT_ALTERNATE_4 0x5 210#define SW_MUX_OUT_ALT3 (0x4 << 4)
211#define SW_MUX_OUT_ALTERNATE_5 0x6 211#define SW_MUX_OUT_ALT4 (0x5 << 4)
212#define SW_MUX_OUT_ALTERNATE_6 0x7 212#define SW_MUX_OUT_ALT5 (0x6 << 4)
213 213#define SW_MUX_OUT_ALT6 (0x7 << 4)
214#define SW_MUX_IN_NO_INPUTS 0x0 214
215#define SW_MUX_IN_GPIO_PSR_ISR 0x1 215#define SW_MUX_IN (0xf << 0)
216#define SW_MUX_IN_FUNCTIONAL 0x2 216#define SW_MUX_IN_NO_INPUTS (0x0 << 0)
217#define SW_MUX_IN_ALTERNATE_1 0x3 217#define SW_MUX_IN_GPIO_PSR_ISR (0x1 << 0)
218#define SW_MUX_IN_ALTERNATE_2 0x4 218#define SW_MUX_IN_FUNCTIONAL (0x2 << 0)
219 219#define SW_MUX_IN_ALT1 (0x4 << 0)
220#define SW_MUX_IN_ALT2 (0x8 << 0)
221
222/* Masks for each signal field */
223#define SW_MUX_CTL_SIG1 (0x7f << 0)
224#define SW_MUX_CTL_SIG2 (0x7f << 8)
225#define SW_MUX_CTL_SIG3 (0x7f << 16)
226#define SW_MUX_CTL_SIG4 (0x7f << 24)
220/* Shift above flags into one of the four fields in each register */ 227/* Shift above flags into one of the four fields in each register */
221#define SW_MUX_CTL_FLD_0(x) ((x) << 0) 228#define SW_MUX_CTL_SIG1w(x) (((x) << 0) & SW_MUX_CTL_SIG1)
222#define SW_MUX_CTL_FLD_1(x) ((x) << 8) 229#define SW_MUX_CTL_SIG2w(x) (((x) << 8) & SW_MUX_CTL_SIG2)
223#define SW_MUX_CTL_FLD_2(x) ((x) << 16) 230#define SW_MUX_CTL_SIG3w(x) (((x) << 16) & SW_MUX_CTL_SIG3)
224#define SW_MUX_CTL_FLD_3(x) ((x) << 24) 231#define SW_MUX_CTL_SIG4w(x) (((x) << 24) & SW_MUX_CTL_SIG4)
225 232
226/* SW_PAD_CTL */ 233/* SW_PAD_CTL */
227#define SW_PAD_CTL_TTM_PAD__X__X IOMUXC_(0x154) 234#define SW_PAD_CTL_TTM_PAD__X__X IOMUXC_(0x154)
@@ -336,36 +343,39 @@
336#define SW_PAD_CTL_CAPTURE_COMPARE_WATCHDOG_RST IOMUXC_(0x308) 343#define SW_PAD_CTL_CAPTURE_COMPARE_WATCHDOG_RST IOMUXC_(0x308)
337 344
338/* SW_PAD_CTL flags */ 345/* SW_PAD_CTL flags */
339#define SW_PAD_CTL_LOOPBACK (1 << 9) 346#define SW_PAD_CTL_LOOPBACK (0x1 << 9) /* Route output to input */
340#define SW_PAD_CTL_DISABLE_PULL_UP_DOWN_AND_KEEPER (0 << 7) 347/* Pullup, pulldown and keeper enable */
341#if 0 /* Same as 0 */ 348#define SW_PAD_CTL_PUE_PKE (0x3 << 7)
342#define SW_PAD_CTL_DISABLE_PULL_UP_DOWN_AND_KEEPER (1 << 7) 349#define SW_PAD_CTL_PUE_PKE_DISABLE (0x0 << 7)
343#endif 350#define SW_PAD_CTL_PUE_PKE_DISABLE_2 (0x1 << 7) /* Same as 0x0 */
344#define SW_PAD_CTL_ENABLE_KEEPER (2 << 7) 351#define SW_PAD_CTL_PUE_PKE_KEEPER (0x2 << 7)
345#define SW_PAD_CTL_ENABLE_PULL_UP_OR_PULL_DOWN (3 << 7) 352#define SW_PAD_CTL_PUE_PKE_PULLUPDOWN (0x3 << 7) /* Enb. Pull up or down */
346#define SW_PAD_CTL_100K_PULL_DOWN (0 << 5) 353/* Pullup/down resistance */
347#define SW_PAD_CTL_100K_PULL_UP (1 << 5) 354#define SW_PAD_CTL_PUS (0x3 << 5)
355#define SW_PAD_CTL_PUS_DOWN_100K (0x0 << 5)
356#define SW_PAD_CTL_PUS_UP_100K (0x1 << 5)
348#if 0 /* Completeness */ 357#if 0 /* Completeness */
349#define SW_PAD_CTL_47K_PULL_UP (2 << 5) /* Not in IMX31/L */ 358#define SW_PAD_CTL_PUS_UP_47K (0x2 << 5) /* Not in IMX31/L */
350#define SW_PAD_CTL_22K_PULL_UP (3 << 5) /* Not in IMX31/L */ 359#define SW_PAD_CTL_PUS_UP_22K (0x3 << 5) /* Not in IMX31/L */
351#endif
352#define SW_PAD_CTL_IPP_HYS_STD (0 << 4)
353#define SW_PAD_CTL_IPP_HYS_SCHIMDT (1 << 4)
354#define SW_PAD_CTL_IPP_ODE_CMOS (0 << 3)
355#define SW_PAD_CTL_IPP_ODE_OPEN (1 << 3)
356#define SW_PAD_CTL_IPP_DSE_STD (0 << 1)
357#define SW_PAD_CTL_IPP_DSE_HIGH (1 << 1)
358#define SW_PAD_CTL_IPP_DSE_MAX (2 << 1)
359#if 0 /* Same as 2 */
360#define SW_PAD_CTL_IPP_DSE_MAX (3 << 1)
361#endif 360#endif
362#define SW_PAD_CTL_IPP_SRE_SLOW (0 << 0) 361#define SW_PAD_CTL_HYS (0x1 << 4) /* Schmitt trigger input */
363#define SW_PAD_CTL_IPP_SRE_FAST (1 << 0) 362#define SW_PAD_CTL_ODE (0x1 << 3) /* Open drain output 0=CMOS pushpull*/
363#define SW_PAD_CTL_DSE (0x3 << 1)
364#define SW_PAD_CTL_DSE_STD (0x0 << 1) /* Drive strength */
365#define SW_PAD_CTL_DSE_HIGH (0x1 << 1)
366#define SW_PAD_CTL_DSE_MAX (0x2 << 1)
367#define SW_PAD_CTL_DSE_MAX_2 (0x3 << 1) /* Same as 0x2 */
368#define SW_PAD_CTL_SRE (0x1 << 0) /* Slew rate, 1=fast */
369
370/* Masks for each IO field */
371#define SW_PAD_CTL_IO1 (0x3ff << 0)
372#define SW_PAD_CTL_IO2 (0x3ff << 10)
373#define SW_PAD_CTL_IO3 (0x3ff << 20)
364 374
365/* Shift above flags into one of the three fields in each register */ 375/* Shift above flags into one of the three fields in each register */
366#define SW_PAD_CTL_FLD_0(x) ((x) << 0) 376#define SW_PAD_CTL_IO1w(x) (((x) << 0) & SW_PAD_CTL_IO1)
367#define SW_PAD_CTL_FLD_1(x) ((x) << 10) 377#define SW_PAD_CTL_IO2w(x) (((x) << 10) & SW_PAD_CTL_IO2)
368#define SW_PAD_CTL_FLD_2(x) ((x) << 20) 378#define SW_PAD_CTL_IO3w(x) (((x) << 20) & SW_PAD_CTL_IO3)
369 379
370/* RNGA */ 380/* RNGA */
371#define RNGA_CONTROL (*(REG32_PTR_T)(RNGA_BASE_ADDR+0x00)) 381#define RNGA_CONTROL (*(REG32_PTR_T)(RNGA_BASE_ADDR+0x00))
diff --git a/firmware/export/power.h b/firmware/export/power.h
index edf43f8cc8..5cd6996eff 100644
--- a/firmware/export/power.h
+++ b/firmware/export/power.h
@@ -95,6 +95,7 @@ bool spdif_powered(void);
95 95
96#if CONFIG_TUNER 96#if CONFIG_TUNER
97bool tuner_power(bool status); 97bool tuner_power(bool status);
98bool tuner_powered(void);
98#endif 99#endif
99 100
100#endif /* _POWER_H_ */ 101#endif /* _POWER_H_ */
diff --git a/firmware/export/si4700.h b/firmware/export/si4700.h
index 89905ee155..fcc71cb282 100644
--- a/firmware/export/si4700.h
+++ b/firmware/export/si4700.h
@@ -36,9 +36,15 @@ struct si4700_region_data
36 36
37extern const struct si4700_region_data si4700_region_data[TUNER_NUM_REGIONS]; 37extern const struct si4700_region_data si4700_region_data[TUNER_NUM_REGIONS];
38 38
39struct si4700_dbg_info
40{
41 uint16_t regs[16]; /* Read registers */
42};
43
39void si4700_init(void); 44void si4700_init(void);
40int si4700_set(int setting, int value); 45int si4700_set(int setting, int value);
41int si4700_get(int setting); 46int si4700_get(int setting);
47void si4700_dbg_info(struct si4700_dbg_info *nfo);
42 48
43#ifndef CONFIG_TUNER_MULTI 49#ifndef CONFIG_TUNER_MULTI
44#define tuner_set si4700_set 50#define tuner_set si4700_set
diff --git a/firmware/target/arm/as3525/power-as3525.c b/firmware/target/arm/as3525/power-as3525.c
index 07867546c2..2fbeab0bc6 100644
--- a/firmware/target/arm/as3525/power-as3525.c
+++ b/firmware/target/arm/as3525/power-as3525.c
@@ -54,9 +54,21 @@ void ide_power_enable(bool on)
54} 54}
55 55
56#if CONFIG_TUNER 56#if CONFIG_TUNER
57static bool tuner_on = false;
58
57bool tuner_power(bool status) 59bool tuner_power(bool status)
58{ 60{
59 (void)status; 61 if (status != tuner_on)
60 return false; 62 {
63 tuner_on = status;
64 status = !status;
65 }
66
67 return status;
68}
69
70bool tuner_powered(void)
71{
72 return tuner_on; /* No debug info */
61} 73}
62#endif 74#endif
diff --git a/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c
index 154e13f9a7..7646402435 100644
--- a/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c
+++ b/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c
@@ -21,6 +21,7 @@
21 ****************************************************************************/ 21 ****************************************************************************/
22#include "config.h" 22#include "config.h"
23#include "system.h" 23#include "system.h"
24#include "mc13783.h"
24#include "i2c-imx31.h" 25#include "i2c-imx31.h"
25#include "fmradio_i2c.h" 26#include "fmradio_i2c.h"
26 27
@@ -33,9 +34,77 @@ static struct i2c_node si4700_i2c_node =
33 .addr = (0x20), 34 .addr = (0x20),
34}; 35};
35 36
37void fmradio_i2c_init(void)
38{
39 /* RST: LOW */
40 imx31_regclr32(&GPIO1_DR, (1 << 26));
41 /* RST: OUT */
42 imx31_regset32(&GPIO1_GDIR, (1 << 26));
43
44 /* I2C2 SCL: IN, I2C2: SDA IN */
45 imx31_regclr32(&GPIO2_GDIR, (3 << 14));
46 /* I2C2 SCL LO, I2C2 SDA LO */
47 imx31_regclr32(&GPIO2_DR, (3 << 14));
48
49 /* open-drain pins - external pullups on PCB. Pullup default but
50 * disabled */
51 imx31_regmod32(&SW_PAD_CTL_DSR_DTE1_RI_DTE1_DCD_DTE1,
52 /* RI_DTE1 (I2C2_SCLK) */
53 SW_PAD_CTL_IO2w(SW_PAD_CTL_PUE_PKE_DISABLE |
54 SW_PAD_CTL_PUS_UP_100K |
55 SW_PAD_CTL_HYS |
56 SW_PAD_CTL_ODE) |
57 /* DCD_DTE1 (I2C2_SDA) */
58 SW_PAD_CTL_IO1w(SW_PAD_CTL_PUE_PKE_DISABLE |
59 SW_PAD_CTL_PUS_UP_100K |
60 SW_PAD_CTL_HYS |
61 SW_PAD_CTL_ODE),
62 SW_PAD_CTL_IO2 | SW_PAD_CTL_IO1);
63 /* set outputs to I2C2 */
64 imx31_regmod32(&SW_MUX_CTL_RI_DTE1_DCD_DTE1_DTR_DCE2_RXD2,
65 /* RI_DTE1 => I2C2_SCLK */
66 SW_MUX_CTL_SIG4w(SW_MUX_OUT_ALT2 | SW_MUX_IN_ALT2) |
67 /* DCD_DTE1 => I2C2_SDA */
68 SW_MUX_CTL_SIG3w(SW_MUX_OUT_ALT2 | SW_MUX_IN_ALT2),
69 SW_MUX_CTL_SIG4 | SW_MUX_CTL_SIG3);
70}
71
36void fmradio_i2c_enable(bool enable) 72void fmradio_i2c_enable(bool enable)
37{ 73{
38 i2c_enable_node(&si4700_i2c_node, enable); 74 if (enable)
75 {
76 uint32_t io_pin_mux = SW_MUX_CTL_RI_DTE1_DCD_DTE1_DTR_DCE2_RXD2;
77 /* place in GPIO mode to hold SDIO low during RESET release,
78 * SEN1 should be high already (pullup) and GPIO3 left alone */
79 imx31_regset32(&GPIO2_GDIR, (1 << 15)); /* SDIO OUT */
80 /* I2C2_SDA => MCU2_15 */
81 imx31_regmod32(&SW_MUX_CTL_RI_DTE1_DCD_DTE1_DTR_DCE2_RXD2,
82 SW_MUX_CTL_SIG3w(SW_MUX_OUT_GPIO_DR | SW_MUX_IN_GPIO_PSR_ISR),
83 SW_MUX_CTL_SIG3);
84 /* enable CLK32KMCU clock */
85 mc13783_set(MC13783_POWER_CONTROL0, MC13783_CLK32KMCUEN);
86 /* enable the fm chip (release RESET) */
87 imx31_regset32(&GPIO1_DR, (1 << 26));
88 sleep(HZ/100);
89 /* busmode should be selected - OK to release SDIO */
90 imx31_regclr32(&GPIO2_GDIR, (1 << 15)); /* SDIO IN */
91 /* restore pin mux (DCD_DTE1 => I2C2_SDA) */
92 imx31_regmod32(&SW_MUX_CTL_RI_DTE1_DCD_DTE1_DTR_DCE2_RXD2,
93 io_pin_mux, SW_MUX_CTL_SIG3);
94 /* the si4700 is the only thing connected to i2c2 so
95 we can diable the i2c module when not in use */
96 i2c_enable_node(&si4700_i2c_node, true);
97 }
98 else
99 {
100 /* the si4700 is the only thing connected to i2c2 so
101 we can diable the i2c module when not in use */
102 i2c_enable_node(&si4700_i2c_node, false);
103 /* disable the fm chip */
104 imx31_regclr32(&GPIO1_DR, (1 << 26));
105 /* disable CLK32KMCU clock */
106 mc13783_clear(MC13783_POWER_CONTROL0, MC13783_CLK32KMCUEN);
107 }
39} 108}
40 109
41int fmradio_i2c_write(unsigned char address, const unsigned char* buf, int count) 110int fmradio_i2c_write(unsigned char address, const unsigned char* buf, int count)
@@ -52,3 +121,7 @@ int fmradio_i2c_read(unsigned char address, unsigned char* buf, int count)
52 return 0; 121 return 0;
53} 122}
54 123
124int si4700_st(void)
125{
126 return (GPIO1_DR & (1 << 28)) >> 28;
127}
diff --git a/firmware/target/arm/imx31/gigabeat-s/power-imx31.c b/firmware/target/arm/imx31/gigabeat-s/power-imx31.c
index 727b38bd96..b29d3cd0fb 100644
--- a/firmware/target/arm/imx31/gigabeat-s/power-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/power-imx31.c
@@ -98,37 +98,24 @@ bool ide_powered(void)
98} 98}
99 99
100#if CONFIG_TUNER 100#if CONFIG_TUNER
101static bool tuner_on = false;
102
101bool tuner_power(bool status) 103bool tuner_power(bool status)
102{ 104{
103 static bool tuner_powered = false; 105 if (status != tuner_on)
104
105 if (status == tuner_powered)
106 return status;
107
108 tuner_powered = status;
109
110 if (status)
111 {
112 /* the si4700 is the only thing connected to i2c2 so
113 we can diable the i2c module when not in use */
114 fmradio_i2c_enable(true);
115 /* enable the fm chip */
116 imx31_regset32(&GPIO1_DR, (1 << 26));
117 /* enable CLK32KMCU clock */
118 mc13783_set(MC13783_POWER_CONTROL0, MC13783_CLK32KMCUEN);
119 }
120 else
121 { 106 {
122 /* the si4700 is the only thing connected to i2c2 so 107 tuner_on = status;
123 we can diable the i2c module when not in use */ 108 /* Handle power and pin setup */
124 fmradio_i2c_enable(false); 109 fmradio_i2c_enable(status);
125 /* disable the fm chip */ 110 status = !status;
126 imx31_regclr32(&GPIO1_DR, (1 << 26));
127 /* disable CLK32KMCU clock */
128 mc13783_clear(MC13783_POWER_CONTROL0, MC13783_CLK32KMCUEN);
129 } 111 }
130 112
131 return !status; 113 return status;
114}
115
116bool tuner_powered(void)
117{
118 return tuner_on;
132} 119}
133#endif /* #if CONFIG_TUNER */ 120#endif /* #if CONFIG_TUNER */
134 121
@@ -151,6 +138,10 @@ void power_off(void)
151 138
152void power_init(void) 139void power_init(void)
153{ 140{
141#if CONFIG_TUNER
142 fmradio_i2c_init();
143#endif
144
154 /* Poll initial state */ 145 /* Poll initial state */
155 charger_main_detect_event(); 146 charger_main_detect_event();
156 147
diff --git a/firmware/tuner.c b/firmware/tuner.c
index c694031c45..c5da27079c 100644
--- a/firmware/tuner.c
+++ b/firmware/tuner.c
@@ -64,7 +64,7 @@ const struct si4700_region_data si4700_region_data[TUNER_NUM_REGIONS] =
64{ 64{
65 [REGION_EUROPE] = { 1, 0, 2 }, /* 50uS, US/Europe band, 50kHz spacing */ 65 [REGION_EUROPE] = { 1, 0, 2 }, /* 50uS, US/Europe band, 50kHz spacing */
66 [REGION_US_CANADA] = { 0, 0, 0 }, /* 75uS, US/Europe band, 200kHz spacing */ 66 [REGION_US_CANADA] = { 0, 0, 0 }, /* 75uS, US/Europe band, 200kHz spacing */
67 [REGION_JAPAN] = { 1, 1, 1 }, /* 50uS, Japanese band, 100kHz spacing */ 67 [REGION_JAPAN] = { 1, 2, 1 }, /* 50uS, Japanese band, 100kHz spacing */
68 [REGION_KOREA] = { 1, 0, 1 }, /* 50uS, US/Europe band, 100kHz spacing */ 68 [REGION_KOREA] = { 1, 0, 1 }, /* 50uS, US/Europe band, 100kHz spacing */
69}; 69};
70#endif /* (CONFIG_TUNER & SI4700) */ 70#endif /* (CONFIG_TUNER & SI4700) */