si4700 tuner: lower stereo switchover range, so it switches to stereo for weaker...
[maemo-rb.git] / firmware / drivers / tuner / si4700.c
blobdfc0e46cafbdbd67c49d9e4ed4b20b489e8208dd
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Tuner "middleware" for Silicon Labs SI4700 chip
12 * Copyright (C) 2008 Nils Wallménius
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
23 #include "config.h"
24 #include <stdbool.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include "kernel.h"
28 #include "power.h"
29 #include "tuner.h" /* tuner abstraction interface */
30 #include "fmradio.h"
31 #include "fmradio_i2c.h" /* physical interface driver */
33 /* some models use the internal 32 kHz oscillator which needs special attention
34 during initialisation, power-up and power-down.
36 #if defined(SANSA_CLIP) || defined(SANSA_E200V2) || defined(SANSA_FUZE) || defined(SANSA_C200V2)
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)
42 extern int si4700_st(void);
43 #endif
45 #ifndef SI4700_GPIO_SETUP
46 #define SI4700_GPIO_SETUP 0
47 #endif
49 #define SEEK_THRESHOLD 0x16
51 #define I2C_ADR 0x20
53 /** Registers and bits - "x" denotes Si4702/03 only (so they say) **/
54 #define DEVICEID 0x0
55 #define CHIPID 0x1
56 #define POWERCFG 0x2
57 #define CHANNEL 0x3
58 #define SYSCONFIG1 0x4
59 #define SYSCONFIG2 0x5
60 #define SYSCONFIG3 0x6
61 #define TEST1 0x7
62 #define TEST2 0x8
63 #define BOOTCONFIG 0x9
64 #define STATUSRSSI 0xA
65 #define READCHAN 0xB
66 #define RDSA 0xC /* x */
67 #define RDSB 0xD /* x */
68 #define RDSC 0xE /* x */
69 #define RDSD 0xF /* x */
71 /* DEVICEID (0x0) */
72 #define DEVICEID_PN (0xf << 12)
73 /* 0x01 = Si4700/01 */
74 /* 0x01 = Si4702/03 */
75 #define DEVICEID_MFGID (0xfff << 0)
76 /* always 0x242 */
78 /* CHIPID (0x1) */
80 #if 0 /* Informational */
81 /* Si4700/01 */
82 #define CHIPID_REV (0x3f << 10)
83 #define CHIPID_DEV (0x1 << 9)
84 /* 0 before powerup */
85 /* 0 after powerup = Si4700 */
86 /* 1 after powerup = Si4701 */
87 #define CHIPID_FIRMWARE (0xff << 0)
89 /* Si4702/03 */
90 #define CHIPID_REV (0x3f << 10)
91 #define CHIPID_DEV (0xf << 6)
92 /* 0000 before PU = Si4702 */
93 /* 0001 after PU = Si4702 */
94 /* 1000 before PU = Si4703 */
95 /* 1001 after PU = Si4703 */
96 #define CHIPID_FIRMWARE (0x3f << 0)
97 #endif /* 0 */
99 /* POWERCFG (0x2) */
100 #define POWERCFG_DSMUTE (0x1 << 15)
101 #define POWERCFG_DMUTE (0x1 << 14)
102 #define POWERCFG_MONO (0x1 << 13)
103 #define POWERCFG_RDSM (0x1 << 11) /* x */
104 #define POWERCFG_SKMODE (0x1 << 10)
105 #define POWERCFG_SEEKUP (0x1 << 9)
106 #define POWERCFG_SEEK (0x1 << 8)
107 #define POWERCFG_DISABLE (0x1 << 6)
108 #define POWERCFG_ENABLE (0x1 << 0)
110 /* CHANNEL (0x3) */
111 #define CHANNEL_TUNE (0x1 << 15)
112 #define CHANNEL_CHAN (0x3ff << 0)
113 #define CHANNEL_CHANw(x) ((x) & CHANNEL_CHAN)
115 /* SYSCONFIG1 (0x4) */
116 #define SYSCONFIG1_RDSIEN (0x1 << 15) /* x */
117 #define SYSCONFIG1_STCIEN (0x1 << 14)
118 #define SYSCONFIG1_RDS (0x1 << 12) /* x */
119 #define SYSCONFIG1_DE (0x1 << 11)
120 #define SYSCONFIG1_AGCD (0x1 << 10)
121 #define SYSCONFIG1_BLNDADJ (0x3 << 6)
122 #define SYSCONFIG1_BLNDADJ_31_39_RSSI (0x0 << 6)
123 #define SYSCONFIG1_BLNDADJ_37_55_RSSI (0x1 << 6)
124 #define SYSCONFIG1_BLNDADJ_19_37_RSSI (0x2 << 6)
125 #define SYSCONFIG1_BLNDADJ_25_43_RSSI (0x3 << 6)
126 #define SYSCONFIG1_GPIO3 (0x3 << 4)
127 #define SYSCONFIG1_GPIO3_HI_Z (0x0 << 4)
128 #define SYSCONFIG1_GPIO3_MO_ST_I (0x1 << 4)
129 #define SYSCONFIG1_GPIO3_LOW (0x2 << 4)
130 #define SYSCONFIG1_GPIO3_HI (0x3 << 4)
131 #define SYSCONFIG1_GPIO2 (0x3 << 2)
132 #define SYSCONFIG1_GPIO2_HI_Z (0x0 << 2)
133 #define SYSCONFIG1_GPIO2_STC_RDS_I (0x1 << 2)
134 #define SYSCONFIG1_GPIO2_LOW (0x2 << 2)
135 #define SYSCONFIG1_GPIO2_HI (0x3 << 2)
136 #define SYSCONFIG1_GPIO1 (0x3 << 0)
137 #define SYSCONFIG1_GPIO1_HI_Z (0x0 << 0)
138 #define SYSCONFIG1_GPIO1_LOW (0x2 << 0)
139 #define SYSCONFIG1_GPIO1_HI (0x3 << 0)
141 /* SYSCONFIG2 (0x5) */
142 #define SYSCONFIG2_SEEKTH (0xff << 8)
143 #define SYSCONFIG2_SKEETHw(x) (((x) << 8) & SYSCONFIG2_SEEKTH)
144 #define SYSCONFIG2_BAND (0x3 << 6)
145 #define SYSCONFIG2_BANDw(x) (((x) << 6) & SYSCONFIG2_BAND)
146 #define SYSCONFIG2_BANDr(x) (((x) & SYSCONFIG2_BAND) >> 6)
147 #define SYSCONFIG2_BAND_875_1080 (0x0 << 6) /* tenth-megahertz */
148 #define SYSCONFIG2_BAND_760_1080 (0x1 << 6)
149 #define SYSCONFIG2_BAND_760_900 (0x2 << 6)
150 #define SYSCONFIG2_SPACE (0x3 << 4)
151 #define SYSCONFIG2_SPACEw(x) (((x) << 4) & SYSCONFIG2_SPACE)
152 #define SYSCONFIG2_SPACEr(x) (((x) & SYSCONFIG2_SPACE) >> 4)
153 #define SYSCONFIG2_SPACE_200KHZ (0x0 << 4)
154 #define SYSCONFIG2_SPACE_100KHZ (0x1 << 4)
155 #define SYSCONFIG2_SPACE_50KHZ (0x2 << 4)
156 /* 4700/01 0000=mute,0001=-28dBFS..2dB steps..1111= +0dBFS */
157 /* 4702/03: VOLEXT=0: 0000=mute,0001=-28dBFS..2dB steps..1111= +0dBFS */
158 /* VOLEXT=1: 0000=mute,0001=-58dBFS..2dB steps..1111=-30dBFS */
159 #define SYSCONFIG2_VOLUME (0xf << 0)
160 #define SYSCONFIG2_VOLUMEw(x) ((x) & SYSCONFIG2_VOLUME)
162 /* SYSCONFIG3 (0x6) */
163 #define SYSCONFIG3_SMUTER (0x3 << 14)
164 #define SYSCONFIG3_SMUTER_FASTEST (0x0 << 14)
165 #define SYSCONFIG3_SMUTER_FAST (0x1 << 14)
166 #define SYSCONFIG3_SMUTER_SLOW (0x2 << 14)
167 #define SYSCONFIG3_SMUTER_SLOWEST (0x3 << 14)
168 #define SYSCONFIG3_SMUTEA (0x3 << 12)
169 #define SYSCONFIG3_SMUTEA_16DB (0x0 << 12)
170 #define SYSCONFIG3_SMUTEA_14DB (0x1 << 12)
171 #define SYSCONFIG3_SMUTEA_12DB (0x2 << 12)
172 #define SYSCONFIG3_SMUTEA_10DB (0x3 << 12)
173 #define SYSCONFIG3_VOLEXT (0x1 << 8) /* x */
174 #define SYSCONFIG3_SKSNR (0xf << 4)
175 #define SYSCONFIG3_SKSNRw(x) (((x) << 4) & SYSCONFIG3_SKSNR)
176 #define SYSCONFIG3_SKCNT (0xf << 0)
177 #define SYSCONFIG3_SKCNTw(x) (((x) << 0) & SYSCONFIG3_SKCNT)
179 /* TEST1 (0x7) */
180 /* 4700/01: 15=always 0, 13:0 = write with preexisting values! */
181 /* 4702/03: 13:0 = write with preexisting values! */
182 #define TEST1_XOSCEN (0x1 << 15) /* x */
183 #define TEST1_AHIZEN (0x1 << 14)
185 /* TEST2 (0x8) */
186 /* 15:0 = write with preexisting values! */
188 /* BOOTCONFIG (0x9) */
189 /* 15:0 = write with preexisting values! */
191 /* STATUSRSSI (0xA) */
192 #define STATUSRSSI_RDSR (0x1 << 15) /* x */
193 #define STATUSRSSI_STC (0x1 << 14)
194 #define STATUSRSSI_SFBL (0x1 << 13)
195 #define STATUSRSSI_AFCRL (0x1 << 12)
196 #define STATUSRSSI_RDSS (0x1 << 11) /* x */
197 #define STATUSRSSI_BLERA (0x3 << 9) /* x */
198 #define STATUSRSSI_ST (0x1 << 8)
199 #define STATUSRSSI_RSSI (0xff << 0)
200 #define STATUSRSSI_RSSIr(x) ((x) & 0xff)
202 /* READCHAN (0xB) */
203 #define READCHAN_BLERB (0x3 << 14) /* x */
204 #define READCHAN_BLERC (0x3 << 12) /* x */
205 #define READCHAN_BLERD (0x3 << 10) /* x */
206 #define READCHAN_READCHAN (0x3ff << 0)
208 /* RDSA-D (0xC-0xF) */
209 /* 4702/03: RDS Block A-D data */
211 static bool tuner_present = false;
212 static int curr_frequency = 87500000; /* Current station frequency (HZ) */
213 static uint16_t cache[16];
215 /* reads <len> registers from radio at offset 0x0A into cache */
216 static void si4700_read(int len)
218 int i;
219 unsigned char buf[32];
220 unsigned char *ptr = buf;
221 uint16_t data;
223 fmradio_i2c_read(I2C_ADR, buf, len * 2);
224 for (i = 0; i < len; i++) {
225 data = ptr[0] << 8 | ptr[1];
226 cache[(i + STATUSRSSI) & 0xF] = data;
227 ptr += 2;
231 /* writes <len> registers from cache to radio at offset 0x02 */
232 static void si4700_write(int len)
234 int i;
235 unsigned char buf[32];
236 unsigned char *ptr = buf;
237 uint16_t data;
239 for (i = 0; i < len; i++) {
240 data = cache[(i + POWERCFG) & 0xF];
241 *ptr++ = (data >> 8) & 0xFF;
242 *ptr++ = data & 0xFF;
244 fmradio_i2c_write(I2C_ADR, buf, len * 2);
247 /* Hide silly, wrapped and continuous register reading and make interface
248 * appear sane and normal. This also makes the driver compatible with
249 * using the 3-wire interface. */
250 static uint16_t si4700_read_reg(int reg)
252 si4700_read(((reg - STATUSRSSI) & 0xF) + 1);
253 return cache[reg];
256 static void si4700_write_reg(int reg, uint16_t value)
258 cache[reg] = value;
259 si4700_write(((reg - POWERCFG) & 0xF) + 1);
262 static void si4700_write_masked(int reg, uint16_t bits, uint16_t mask)
264 si4700_write_reg(reg, (cache[reg] & ~mask) | (bits & mask));
267 static void si4700_write_set(int reg, uint16_t mask)
269 si4700_write_reg(reg, cache[reg] | mask);
272 static void si4700_write_clear(int reg, uint16_t mask)
274 si4700_write_reg(reg, cache[reg] & ~mask);
277 #if (SI4700_GPIO_SETUP & SYSCONFIG1_GPIO3) != SYSCONFIG1_GPIO3_MO_ST_I
278 /* Poll i2c for the stereo status */
279 static inline int si4700_st(void)
281 return (si4700_read_reg(STATUSRSSI) & STATUSRSSI_ST) >> 8;
283 #endif
285 static void si4700_sleep(int snooze)
287 if (snooze)
289 /** power down **/
290 /* ENABLE high, DISABLE high */
291 si4700_write_set(POWERCFG,
292 POWERCFG_DISABLE | POWERCFG_ENABLE);
293 /* Bits self-clear once placed in powerdown. */
294 cache[POWERCFG] &= ~(POWERCFG_DISABLE | POWERCFG_ENABLE);
296 else
298 /** power up **/
299 /* ENABLE high, DISABLE low */
300 si4700_write_masked(POWERCFG, POWERCFG_ENABLE,
301 POWERCFG_DISABLE | POWERCFG_ENABLE);
302 sleep(110 * HZ / 1000);
304 /* init register cache */
305 si4700_read(16);
307 #if SI4700_GPIO_SETUP != 0
308 si4700_write_masked(SYSCONFIG1, SI4700_GPIO_SETUP,
309 SYSCONFIG1_GPIO1 | SYSCONFIG1_GPIO2 |
310 SYSCONFIG1_GPIO3);
311 #endif
312 /* set mono->stereo switching RSSI range to lowest setting */
313 si4700_write_masked(SYSCONFIG1, SYSCONFIG1_BLNDADJ_19_37_RSSI,
314 SYSCONFIG1_BLNDADJ);
316 si4700_write_masked(SYSCONFIG2,
317 SYSCONFIG2_SKEETHw(SEEK_THRESHOLD) |
318 SYSCONFIG2_VOLUMEw(0xF),
319 SYSCONFIG2_VOLUME | SYSCONFIG2_SEEKTH);
323 bool si4700_detect(void)
325 bool detected;
327 tuner_power(true);
328 detected = (si4700_read_reg(DEVICEID) == 0x1242);
329 tuner_power(false);
331 return detected;
334 void si4700_init(void)
336 /* check device id */
337 if (si4700_detect()) {
338 tuner_present = true;
340 tuner_power(true);
342 /* read all registers */
343 si4700_read(16);
344 si4700_sleep(0);
346 #ifdef USE_INTERNAL_OSCILLATOR
347 /* Enable the internal oscillator
348 (Si4702-16 needs this register to be initialised to 0x100) */
349 si4700_write_set(TEST1, TEST1_XOSCEN | 0x100);
350 sleep(HZ/2);
351 #endif
353 si4700_sleep(1);
354 tuner_power(false);
358 static void si4700_set_frequency(int freq)
360 static const unsigned int spacings[3] =
362 200000, /* SYSCONFIG2_SPACE_200KHZ */
363 100000, /* SYSCONFIG2_SPACE_100KHZ */
364 50000, /* SYSCONFIG2_SPACE_50KHZ */
366 static const unsigned int bands[3] =
368 87500000, /* SYSCONFIG2_BAND_875_1080 */
369 76000000, /* SYSCONFIG2_BAND_760_1080 */
370 76000000, /* SYSCONFIG2_BAND_760_900 */
373 /* check BAND and spacings */
374 int space = SYSCONFIG2_SPACEr(cache[SYSCONFIG2]);
375 int band = SYSCONFIG2_BANDr(cache[SYSCONFIG2]);
376 int chan = (freq - bands[band]) / spacings[space];
377 int readchan;
379 curr_frequency = freq;
383 /* tuning should be done within 60 ms according to the datasheet */
384 si4700_write_reg(CHANNEL, CHANNEL_CHANw(chan) | CHANNEL_TUNE);
385 sleep(HZ * 60 / 1000);
387 /* get tune result */
388 readchan = si4700_read_reg(READCHAN) & READCHAN_READCHAN;
390 si4700_write_clear(CHANNEL, CHANNEL_TUNE);
391 } while (!((cache[STATUSRSSI] & STATUSRSSI_STC) && (readchan == chan)));
394 static int si4700_tuned(void)
396 /* Primitive tuning check: sufficient level and AFC not railed */
397 uint16_t status = si4700_read_reg(STATUSRSSI);
398 if (STATUSRSSI_RSSIr(status) >= SEEK_THRESHOLD &&
399 (status & STATUSRSSI_AFCRL) == 0)
400 return 1;
402 return 0;
405 static void si4700_set_region(int region)
407 const struct fm_region_data *rd = &fm_region_data[region];
409 int band = (rd->freq_min == 76000000) ? 2 : 0;
410 int spacing = (100000 / rd->freq_step);
411 int deemphasis = (rd->deemphasis == 50) ? SYSCONFIG1_DE : 0;
413 uint16_t bandspacing = SYSCONFIG2_BANDw(band) |
414 SYSCONFIG2_SPACEw(spacing);
415 uint16_t oldbs = cache[SYSCONFIG2] & (SYSCONFIG2_BAND | SYSCONFIG2_SPACE);
417 si4700_write_masked(SYSCONFIG1, deemphasis, SYSCONFIG1_DE);
418 si4700_write_masked(SYSCONFIG2, bandspacing,
419 SYSCONFIG2_BAND | SYSCONFIG2_SPACE);
421 /* Retune if this region change would change the channel number. */
422 if (oldbs != bandspacing)
423 si4700_set_frequency(curr_frequency);
426 /* tuner abstraction layer: set something to the tuner */
427 int si4700_set(int setting, int value)
429 switch(setting)
431 case RADIO_SLEEP:
432 if (value != 2)
433 si4700_sleep(value);
434 /* else actually it's 'pause' */
435 break;
437 case RADIO_FREQUENCY:
438 si4700_set_frequency(value);
439 break;
441 case RADIO_SCAN_FREQUENCY:
442 si4700_set_frequency(value);
443 return si4700_tuned();
445 case RADIO_MUTE:
446 si4700_write_masked(POWERCFG, value ? 0 : POWERCFG_DMUTE,
447 POWERCFG_DMUTE);
448 break;
450 case RADIO_REGION:
451 si4700_set_region(value);
452 break;
454 case RADIO_FORCE_MONO:
455 si4700_write_masked(POWERCFG, value ? POWERCFG_MONO : 0,
456 POWERCFG_MONO);
457 break;
459 default:
460 return -1;
463 return 1;
466 /* tuner abstraction layer: read something from the tuner */
467 int si4700_get(int setting)
469 int val = -1; /* default for unsupported query */
471 switch(setting)
473 case RADIO_PRESENT:
474 val = tuner_present ? 1 : 0;
475 break;
477 case RADIO_TUNED:
478 val = si4700_tuned();
479 break;
481 case RADIO_STEREO:
482 val = si4700_st();
483 break;
486 return val;
489 void si4700_dbg_info(struct si4700_dbg_info *nfo)
491 memset(nfo->regs, 0, sizeof (nfo->regs));
493 if (tuner_powered())
495 si4700_read(16);
496 memcpy(nfo->regs, cache, sizeof (nfo->regs));