Prepare new maemo release
[maemo-rb.git] / firmware / drivers / tuner / rda5802.c
blob7b9bea721dd031c71ba7e1b9295b2416841c300b
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Tuner "middleware" for RDA5802 chip present in some Sansa Clip+ players
12 * Copyright (C) 2010 Bertrik Sikken
13 * Copyright (C) 2008 Nils Wallménius (si4700 code that this was based on)
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
24 #include "config.h"
25 #include <stdbool.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include "kernel.h"
29 #include "power.h"
30 #include "tuner.h" /* tuner abstraction interface */
31 #include "fmradio.h"
32 #include "fmradio_i2c.h" /* physical interface driver */
34 #define SEEK_THRESHOLD 0x16
36 #define I2C_ADR 0x20
38 /* define RSSI range */
39 #define RSSI_MIN 0
40 #define RSSI_MAX 70
42 /** Registers and bits **/
43 #define POWERCFG 0x2
44 #define CHANNEL 0x3
45 #define SYSCONFIG1 0x4
46 #define SYSCONFIG2 0x5
47 #define SYSCONFIG3 0x6
48 #define SYSCONFIG4 0x7 /* undocumented */
49 #define SYSCONFIG5 0x8 /* undocumented */
50 #define SYSCONFIG6 0x9 /* undocumented */
51 #define READCHAN 0xA
52 #define STATUSRSSI 0xB
53 #define IDENT 0xC
56 /* POWERCFG (0x2) */
57 #define POWERCFG_DMUTE (0x1 << 14)
58 #define POWERCFG_MONO (0x1 << 13)
59 #define POWERCFG_SOFT_RESET (0x1 << 1)
60 #define POWERCFG_ENABLE (0x1 << 0)
62 /* CHANNEL (0x3) */
63 #define CHANNEL_CHAN (0x3ff << 6)
64 #define CHANNEL_CHANw(x) (((x) << 6) & CHANNEL_CHAN)
65 #define CHANNEL_TUNE (0x1 << 4)
66 #define CHANNEL_BAND (0x3 << 2)
67 #define CHANNEL_BANDw(x) (((x) << 2) & CHANNEL_BAND)
68 #define CHANNEL_BANDr(x) (((x) & CHANNEL_BAND) >> 2)
69 #define CHANNEL_BAND_870_1080 (0x0) /* tenth-megahertz */
70 #define CHANNEL_BAND_760_1080 (0x1)
71 #define CHANNEL_BAND_760_900 (0x2)
72 #define CHANNEL_BAND_650_760 (0x3)
73 #define CHANNEL_SPACE (0x3 << 0)
74 #define CHANNEL_SPACEw(x) (((x) << 0) & CHANNEL_SPACE)
75 #define CHANNEL_SPACEr(x) (((x) & CHANNEL_SPACE) >> 0)
76 #define CHANNEL_SPACE_100KHZ (0x0)
77 #define CHANNEL_SPACE_200KHZ (0x1)
78 #define CHANNEL_SPACE_50KHZ (0x2)
80 /* SYSCONFIG1 (0x4) */
81 #define SYSCONFIG1_DE (0x1 << 11)
82 #define SYSCONFIG1_SOFTMUTE_EN (0x1 << 9)
84 /* SYSCONFIG2 (0x5) */
85 #define SYSCONFIG2_VOLUME (0xF << 0)
87 /* READCHAN (0xA) */
88 #define READCHAN_READCHAN (0x3ff << 0)
89 #define READCHAN_READCHANr(x) (((x) & READCHAN_READCHAN) >> 0)
90 #define READCHAN_STC (0x1 << 14)
91 #define READCHAN_ST (0x1 << 10)
93 /* STATUSRSSI (0xB) */
94 #define STATUSRSSI_RSSI (0x7F << 9)
95 #define STATUSRSSI_RSSIr(x) (((x) & STATUSRSSI_RSSI) >> 9)
96 #define STATUSRSSI_FM_TRUE (0x1 << 8)
98 static bool tuner_present = false;
100 static uint16_t cache[16] = {
101 [POWERCFG] = 0xC401, /* DHIZ, DMUTE, CLK_DIRECT_MODE, ENABLE */
102 [CHANNEL] = 0x0000, /* - */
103 [SYSCONFIG1] = 0x0200, /* SYSCONFIG1_SOFTMUTE_EN */
104 [SYSCONFIG2] = 0x867F, /* INT_MODE (def), SEEKTH=1100b, LNA_PORT_SEL=LNAN,
105 LNA_ICSEL=3.0mA, VOLUME=max */
106 [SYSCONFIG3] = 0x8000, /* I2S slave mode */
107 [SYSCONFIG4] = 0x4712, /* undocumented, affects stereo blend */
108 [SYSCONFIG5] = 0x5EC6, /* undocumented */
109 [SYSCONFIG6] = 0x0000 /* undocumented */
112 /* reads <len> registers from radio at offset 0x0A into cache */
113 static void rda5802_read(int len)
115 int i;
116 unsigned char buf[sizeof(cache)];
117 unsigned char *ptr = buf;
118 uint16_t data;
120 fmradio_i2c_read(I2C_ADR, buf, len * 2);
121 for (i = 0; i < len; i++) {
122 data = ptr[0] << 8 | ptr[1];
123 cache[READCHAN + i] = data;
124 ptr += 2;
128 /* writes <len> registers from cache to radio at offset 0x02 */
129 static void rda5802_write(int len)
131 int i;
132 unsigned char buf[sizeof(cache)];
133 unsigned char *ptr = buf;
134 uint16_t data;
136 for (i = 0; i < len; i++) {
137 data = cache[POWERCFG + i];
138 *ptr++ = (data >> 8) & 0xFF;
139 *ptr++ = data & 0xFF;
141 fmradio_i2c_write(I2C_ADR, buf, len * 2);
144 static uint16_t rda5802_read_reg(int reg)
146 rda5802_read((reg - READCHAN) + 1);
147 return cache[reg];
150 static void rda5802_write_reg(int reg, uint16_t value)
152 cache[reg] = value;
155 static void rda5802_write_cache(void)
157 rda5802_write(5);
160 static void rda5802_write_masked(int reg, uint16_t bits, uint16_t mask)
162 rda5802_write_reg(reg, (cache[reg] & ~mask) | (bits & mask));
165 static void rda5802_write_clear(int reg, uint16_t mask)
167 rda5802_write_reg(reg, cache[reg] & ~mask);
170 static void rda5802_write_set(int reg, uint16_t mask)
172 rda5802_write_reg(reg, cache[reg] | mask);
175 static void rda5802_sleep(int snooze)
177 if (snooze) {
178 rda5802_write_clear(POWERCFG, POWERCFG_ENABLE);
180 else {
181 tuner_power(true);
182 rda5802_write_set(POWERCFG, POWERCFG_ENABLE);
184 rda5802_write_cache();
185 if(snooze)
186 tuner_power(false);
189 bool rda5802_detect(void)
191 return ((rda5802_read_reg(IDENT) & 0xFF00) == 0x5800);
194 void rda5802_init(void)
196 if (rda5802_detect()) {
197 tuner_present = true;
199 /* soft-reset */
200 rda5802_write_set(POWERCFG, POWERCFG_SOFT_RESET);
201 rda5802_write(1);
202 rda5802_write_clear(POWERCFG, POWERCFG_SOFT_RESET);
203 sleep(HZ * 10 / 1000);
205 /* write initialisation values */
206 rda5802_write(8);
207 sleep(HZ * 70 / 1000);
211 static void rda5802_set_frequency(int freq)
213 int i;
214 uint16_t readchan;
215 static const int spacings[] = {100000, 200000, 50000, 50000};
216 static const int bandstart[] = {87000000, 76000000, 76000000, 65000000};
218 /* calculate channel number */
219 int start = bandstart[CHANNEL_BANDr(cache[CHANNEL])];
220 int space = spacings[CHANNEL_SPACEr(cache[CHANNEL])];
221 int chan = (freq - start) / space;
223 for (i = 0; i < 5; i++) {
224 /* tune and wait a bit */
225 rda5802_write_masked(CHANNEL, CHANNEL_CHANw(chan) | CHANNEL_TUNE,
226 CHANNEL_CHAN | CHANNEL_TUNE);
227 rda5802_write_cache();
228 sleep(HZ * 70 / 1000);
229 rda5802_write_clear(CHANNEL, CHANNEL_TUNE);
230 rda5802_write_cache();
232 /* check if tuning was successful */
233 readchan = rda5802_read_reg(READCHAN);
234 if (readchan & READCHAN_STC) {
235 if (READCHAN_READCHANr(readchan) == chan) {
236 break;
242 static int rda5802_tuned(void)
244 /* Primitive tuning check: sufficient level and AFC not railed */
245 uint16_t status = rda5802_read_reg(STATUSRSSI);
246 if (STATUSRSSI_RSSIr(status) >= SEEK_THRESHOLD &&
247 (status & STATUSRSSI_FM_TRUE)) {
248 return 1;
251 return 0;
254 static void rda5802_set_region(int region)
256 const struct fm_region_data *rd = &fm_region_data[region];
258 int band = (rd->freq_min == 76000000) ?
259 CHANNEL_BAND_760_900 : CHANNEL_BAND_870_1080;
260 int deemphasis = (rd->deemphasis == 50) ? SYSCONFIG1_DE : 0;
261 int space = (rd->freq_step == 50000) ?
262 CHANNEL_SPACE_50KHZ : CHANNEL_SPACE_100KHZ;
264 rda5802_write_masked(SYSCONFIG1, deemphasis, SYSCONFIG1_DE);
265 rda5802_write_masked(CHANNEL, CHANNEL_BANDw(band), CHANNEL_BAND);
266 rda5802_write_masked(CHANNEL, CHANNEL_SPACEw(space), CHANNEL_SPACE);
267 rda5802_write_cache();
270 static bool rda5802_st(void)
272 return (rda5802_read_reg(READCHAN) & READCHAN_ST);
275 static int rda5802_rssi(void)
277 uint16_t status = rda5802_read_reg(STATUSRSSI);
278 return STATUSRSSI_RSSIr(status);
281 /* tuner abstraction layer: set something to the tuner */
282 int rda5802_set(int setting, int value)
284 switch (setting) {
285 case RADIO_SLEEP:
286 rda5802_sleep(value);
287 break;
289 case RADIO_FREQUENCY:
290 rda5802_set_frequency(value);
291 break;
293 case RADIO_SCAN_FREQUENCY:
294 rda5802_set_frequency(value);
295 return rda5802_tuned();
297 case RADIO_MUTE:
298 rda5802_write_masked(POWERCFG, value ? 0 : POWERCFG_DMUTE,
299 POWERCFG_DMUTE);
300 rda5802_write_cache();
301 break;
303 case RADIO_REGION:
304 rda5802_set_region(value);
305 break;
307 case RADIO_FORCE_MONO:
308 rda5802_write_masked(POWERCFG, value ? POWERCFG_MONO : 0,
309 POWERCFG_MONO);
310 rda5802_write_cache();
311 break;
313 default:
314 return -1;
317 return 1;
320 /* tuner abstraction layer: read something from the tuner */
321 int rda5802_get(int setting)
323 int val = -1; /* default for unsupported query */
325 switch (setting) {
326 case RADIO_PRESENT:
327 val = tuner_present ? 1 : 0;
328 break;
330 case RADIO_TUNED:
331 val = rda5802_tuned();
332 break;
334 case RADIO_STEREO:
335 val = rda5802_st();
336 break;
338 case RADIO_RSSI:
339 val = rda5802_rssi();
340 break;
342 case RADIO_RSSI_MIN:
343 val = RSSI_MIN;
344 break;
346 case RADIO_RSSI_MAX:
347 val = RSSI_MAX;
348 break;
351 return val;
354 void rda5802_dbg_info(struct rda5802_dbg_info *nfo)
356 rda5802_read(6);
357 memcpy(nfo->regs, cache, sizeof (nfo->regs));