summaryrefslogtreecommitdiff
path: root/firmware/tuner_sanyo.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/tuner_sanyo.c')
-rw-r--r--firmware/tuner_sanyo.c909
1 files changed, 909 insertions, 0 deletions
diff --git a/firmware/tuner_sanyo.c b/firmware/tuner_sanyo.c
new file mode 100644
index 0000000000..1f4533b5c0
--- /dev/null
+++ b/firmware/tuner_sanyo.c
@@ -0,0 +1,909 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 * Tuner driver for the Sanyo LV24020LP
10 *
11 * Copyright (C) 2007 Ivan Zupan
12 *
13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
15 *
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
18 *
19 ****************************************************************************/
20
21#include <stdbool.h>
22#include <stdlib.h>
23#include "config.h"
24#include "thread.h"
25#include "kernel.h"
26#include "tuner.h" /* tuner abstraction interface */
27#include "fmradio.h" /* physical interface driver */
28#include "mpeg.h"
29#include "sound.h"
30#include "pp5024.h"
31#include "system.h"
32#include "as3514.h"
33
34#ifndef BOOTLOADER
35
36#if 0
37/* define to enable tuner logging */
38#define SANYO_TUNER_LOG
39#endif
40
41#ifdef SANYO_TUNER_LOG
42#include "sprintf.h"
43#include "file.h"
44
45static int fd_log = -1;
46
47#define TUNER_LOG_OPEN() if (fd_log < 0) \
48 fd_log = creat("/tuner_dump.txt")
49/* syncing required because close() is never called */
50#define TUNER_LOG_SYNC() fsync(fd_log)
51#define TUNER_LOG(s...) fdprintf(fd_log, s)
52#else
53#define TUNER_LOG_OPEN()
54#define TUNER_LOG_SYNC()
55#define TUNER_LOG(s...)
56#endif /* SANYO_TUNER_LOG */
57
58/** tuner register defines **/
59
60/* pins on GPIOH port */
61#define FM_NRW_PIN 3
62#define FM_CLOCK_PIN 4
63#define FM_DATA_PIN 5
64#define FM_CLK_DELAY 1
65
66/* block 1 registers */
67
68/* R */
69#define CHIP_ID 0x00
70
71/* W */
72#define BLK_SEL 0x01
73 #define BLK1 0x01
74 #define BLK2 0x02
75
76/* W */
77#define MSRC_SEL 0x02
78 #define MSR_O (1 << 7)
79 #define AFC_LVL (1 << 6)
80 #define AFC_SPD (1 << 5)
81 #define MSS_SD (1 << 2)
82 #define MSS_FM (1 << 1)
83 #define MSS_IF (1 << 0)
84
85/* W */
86#define FM_OSC 0x03
87
88/* W */
89#define SD_OSC 0x04
90
91/* W */
92#define IF_OSC 0x05
93
94/* W */
95#define CNT_CTRL 0x06
96 #define CNT1_CLR (1 << 7)
97 #define CTAB(x) ((x) & (0x7 << 4))
98 #define CTAB_STOP_2 (0x0 << 4)
99 #define CTAB_STOP_8 (0x1 << 4)
100 #define CTAB_STOP_32 (0x2 << 4)
101 #define CTAB_STOP_128 (0x3 << 4)
102 #define CTAB_STOP_512 (0x4 << 4)
103 #define CTAB_STOP_2048 (0x5 << 4)
104 #define CTAB_STOP_8192 (0x6 << 4)
105 #define CTAB_STOP_32768 (0x7 << 4)
106 #define SWP_CNT_L (1 << 3)
107 #define CNT_EN (1 << 2)
108 #define CNT_SEL (1 << 1)
109 #define CNT_SET (1 << 0)
110
111/* W */
112#define IRQ_MSK 0x08
113 #define IM_MS (1 << 6)
114 #define IRQ_LVL (1 << 3)
115 #define IM_AFC (1 << 2)
116 #define IM_FS (1 << 1)
117 #define IM_CNT2 (1 << 0)
118
119/* W */
120#define FM_CAP 0x09
121
122/* R */
123#define CNT_L 0x0a /* Counter register low value */
124
125/* R */
126#define CNT_H 0x0b /* Counter register high value */
127
128/* R */
129#define CTRL_STAT 0x0c
130 #define AFC_FLG (1 << 0)
131
132/* R */
133#define RADIO_STAT 0x0d
134 #define RSS_MS (1 << 7)
135 #define RSS_FS(x) ((x) & 0x7f)
136 #define RSS_FS_GET(x) ((x) & 0x7f)
137 #define RSS_FS_SET(x) (x)
138/* Note: Reading this register will clear field strength and mono/stereo interrupt. */
139
140/* R */
141#define IRQ_ID 0x0e
142 #define II_CNT2 (1 << 5)
143 #define II_AFC (1 << 3)
144 #define II_FS_MS (1 << 0)
145
146/* W */
147#define IRQ_OUT 0x0f
148
149/* block 2 registers - offset added in order to id and avoid manual
150 switching */
151#define BLK2_START 0x10
152
153/* W */
154#define RADIO_CTRL1 (0x02 + BLK2_START)
155 #define EN_MEAS (1 << 7)
156 #define EN_AFC (1 << 6)
157 #define DIR_AFC (1 << 3)
158 #define RST_AFC (1 << 2)
159
160/* W */
161#define IF_CENTER (0x03 + BLK2_START)
162
163/* W */
164#define IF_BW (0x05 + BLK2_START)
165
166/* W */
167#define RADIO_CTRL2 (0x06 + BLK2_START)
168 #define VREF2 (1 << 7)
169 #define VREF (1 << 6)
170 #define STABI_BP (1 << 5)
171 #define IF_PM_L (1 << 4)
172 #define AGCSP (1 << 1)
173 #define AM_ANT_BSW (1 << 0) /* ?? */
174
175/* W */
176#define RADIO_CTRL3 (0x07 + BLK2_START)
177 #define AGC_SLVL (1 << 7)
178 #define VOLSH (1 << 6)
179 #define TB_ON (1 << 5)
180 #define AMUTE_L (1 << 4)
181 #define SE_FM (1 << 3)
182 #define SE_BE (1 << 1)
183 #define SE_EXT (1 << 0) /* For LV24000=0, LV24001/24002=Ext source enab. */
184
185/* W */
186#define STEREO_CTRL (0x08 + BLK2_START)
187 #define FRCST (1 << 7)
188 #define FMCS(x) ((x) & (0x7 << 4))
189 #define FMCS_GET(x) (((x) & (0x7 << 4)) >> 4)
190 #define FMCS_SET(x) ((x) << 4)
191 #define AUTOSSR (1 << 3)
192 #define PILTCA (1 << 2)
193 #define SD_PM (1 << 1)
194 #define ST_M (1 << 0)
195
196/* W */
197#define AUDIO_CTRL1 (0x09 + BLK2_START)
198 #define TONE_LVL(x) ((x) & (0xf << 4))
199 #define TONE_LVL_GET(x) (((x) & (0xf << 4)) >> 4)
200 #define TONE_LVL_SET(x) ((x) << 4)
201 #define VOL_LVL(x) ((x) & 0xf)
202 #define VOL_LVL_GET(x) ((x) & 0xf)
203 #define VOL_LVL_SET(x) ((x) << 4)
204
205/* W */
206#define AUDIO_CTRL2 (0x0a + BLK2_START)
207 #define BASS_PP (1 << 0)
208 #define BASS_P (1 << 1) /* BASS_P, BASS_N are mutually-exclusive */
209 #define BASS_N (1 << 2)
210 #define TREB_P (1 << 3) /* TREB_P, TREB_N are mutually-exclusive */
211 #define TREB_N (1 << 4)
212 #define DEEMP (1 << 5)
213 #define BPFREQ(x) ((x) & (0x3 << 6))
214 #define BPFREQ_2_0K (0x0 << 6)
215 #define BPFREQ_1_0K (0x1 << 6)
216 #define BPFREQ_0_5K (0x2 << 6)
217 #define BPFREQ_HIGH (0x3 << 6)
218
219/* W */
220#define PW_SCTRL (0x0b + BLK2_START)
221 #define SS_CTRL(x) ((x) & (0x7 << 5))
222 #define SS_CTRL_GET(x) (((x) & (0x7 << 5)) >> 5)
223 #define SS_CTRL_SET(x) ((x) << 5)
224 #define SM_CTRL(x) ((x) & (0x7 << 2))
225 #define SM_CTRL_GET(x) (((x) & (0x7 << 2)) >> 2)
226 #define SM_CTRL_SET(x) ((x) << 2)
227 #define PW_HPA (1 << 1) /* LV24002 only */
228 #define PW_RAD (1 << 0)
229
230/* shadow for writeable registers */
231#define TUNER_POWERED (1 << 0)
232#define TUNER_PRESENT (1 << 1)
233#define TUNER_AWAKE (1 << 2)
234#define TUNER_PRESENCE_CHECKED (1 << 3)
235static unsigned tuner_status = 0;
236
237static unsigned char sanyo_regs[0x1c];
238
239static const int sw_osc_low = 10; /* 30; */
240static const int sw_osc_high = 240; /* 200; */
241static const int sw_cap_low = 0;
242static const int sw_cap_high = 191;
243
244/* linear coefficients used for tuning */
245static int coef_00, coef_01, coef_10, coef_11;
246
247/* DAC control register set values */
248int if_set, sd_set;
249
250static inline bool tuner_awake(void)
251{
252 return (tuner_status & TUNER_AWAKE) != 0;
253}
254
255/* send a byte to the tuner - expects write mode to be current */
256static void tuner_sanyo_send_byte(unsigned int byte)
257{
258 int i;
259
260 byte <<= FM_DATA_PIN;
261
262 for (i = 0; i < 8; i++)
263 {
264 GPIOH_OUTPUT_VAL &= ~(1 << FM_CLOCK_PIN);
265
266 GPIOH_OUTPUT_VAL = (GPIOH_OUTPUT_VAL & ~(1 << FM_DATA_PIN)) |
267 (byte & (1 << FM_DATA_PIN));
268
269 GPIOH_OUTPUT_VAL |= (1 << FM_CLOCK_PIN);
270 udelay(FM_CLK_DELAY);
271
272 byte >>= 1;
273 }
274}
275
276/* end a write cycle on the tuner */
277static void tuner_sanyo_end_write(void)
278{
279 /* switch back to read mode */
280 GPIOH_OUTPUT_EN &= ~(1 << FM_DATA_PIN);
281 GPIOH_OUTPUT_VAL &= ~(1 << FM_NRW_PIN);
282}
283
284/* prepare a write cycle on the tuner */
285static unsigned int tuner_sanyo_begin_write(unsigned int address)
286{
287 /* Get register's block, translate address */
288 unsigned int blk = (address >= BLK2_START) ?
289 (address -= BLK2_START, BLK2) : BLK1;
290
291 for (;;)
292 {
293 /* Prepare 3-wire bus pins for write cycle */
294 GPIOH_OUTPUT_VAL |= (1 << FM_NRW_PIN);
295 GPIOH_OUTPUT_EN |= (1 << FM_DATA_PIN);
296
297 udelay(FM_CLK_DELAY);
298
299 /* current block == register block? */
300 if (blk == sanyo_regs[BLK_SEL])
301 return address;
302
303 /* switch block */
304 sanyo_regs[BLK_SEL] = blk;
305
306 /* data first */
307 tuner_sanyo_send_byte(blk);
308 /* then address */
309 tuner_sanyo_send_byte(BLK_SEL);
310
311 tuner_sanyo_end_write();
312
313 udelay(FM_CLK_DELAY);
314 }
315}
316
317/* write a byte to a tuner register */
318static void tuner_sanyo_write(unsigned int address, unsigned int data)
319{
320 /* shadow logical values but do logical=>physical remappings on some
321 registers' data. */
322 sanyo_regs[address] = data;
323
324 switch (address)
325 {
326 case FM_OSC:
327 /* L: 000..255
328 * P: 255..000 */
329 data = 255 - data;
330 break;
331 case FM_CAP:
332 /* L: 000..063, 064..191
333 * P: 255..192, 127..000 */
334 data = ((data < 64) ? 255 : (255 - 64)) - data;
335 break;
336 case RADIO_CTRL1:
337 /* L: data
338 * P: data | always "1" bits */
339 data |= (1 << 4) | (1 << 1) | (1 << 0);
340 break;
341 }
342
343 address = tuner_sanyo_begin_write(address);
344
345 /* data first */
346 tuner_sanyo_send_byte(data);
347 /* then address */
348 tuner_sanyo_send_byte(address);
349
350 tuner_sanyo_end_write();
351}
352
353/* helpers to set/clear register bits */
354static void tuner_sanyo_write_or(unsigned int address, unsigned int bits)
355{
356 tuner_sanyo_write(address, sanyo_regs[address] | bits);
357}
358
359static void tuner_sanyo_write_and(unsigned int address, unsigned int bits)
360{
361 tuner_sanyo_write(address, sanyo_regs[address] & bits);
362}
363
364/* read a byte from a tuner register */
365static unsigned int tuner_sanyo_read(unsigned int address)
366{
367 int i;
368 unsigned int toread;
369
370 address = tuner_sanyo_begin_write(address);
371
372 /* address */
373 tuner_sanyo_send_byte(address);
374
375 tuner_sanyo_end_write();
376
377 /* data */
378 toread = 0;
379 for (i = 0; i < 8; i++)
380 {
381 GPIOH_OUTPUT_VAL &= ~(1 << FM_CLOCK_PIN);
382 udelay(FM_CLK_DELAY);
383
384 toread |= (GPIOH_INPUT_VAL & (1 << FM_DATA_PIN)) << i;
385
386 GPIOH_OUTPUT_VAL |= (1 << FM_CLOCK_PIN);
387 }
388
389 return toread >> FM_DATA_PIN;
390}
391
392/* enables auto frequency centering */
393static void enable_afc(bool enabled)
394{
395 unsigned int radio_ctrl1 = sanyo_regs[RADIO_CTRL1];
396
397 if (enabled)
398 {
399 radio_ctrl1 &= ~RST_AFC;
400 radio_ctrl1 |= EN_AFC;
401 }
402 else
403 {
404 radio_ctrl1 |= RST_AFC;
405 radio_ctrl1 &= ~EN_AFC;
406 }
407
408 tuner_sanyo_write(RADIO_CTRL1, radio_ctrl1);
409}
410
411static int calculate_coef(unsigned fkhz)
412{
413 /* Overflow below 66000kHz --
414 My tuner tunes down to a min of ~72600kHz but datasheet mentions
415 66000kHz as the minimum. ?? Perhaps 76000kHz was intended? */
416 return fkhz < 66000 ?
417 0x7fffffff : 0x81d1a47efc5cb700ull / ((uint64_t)fkhz*fkhz);
418}
419
420static int interpolate_x(int expected_y, int x1, int x2, int y1, int y2)
421{
422 return y1 == y2 ?
423 0 : (int64_t)(expected_y - y1)*(x2 - x1) / (y2 - y1) + x1;
424}
425
426static int interpolate_y(int expected_x, int x1, int x2, int y1, int y2)
427{
428 return x1 == x2 ?
429 0 : (int64_t)(expected_x - x1)*(y2 - y1) / (x2 - x1) + y1;
430}
431
432/* this performs measurements of IF, FM and Stereo frequencies
433 * Input can be: MSS_FM, MSS_IF, MSS_SD */
434static int tuner_measure(unsigned char type, int scale, int duration)
435{
436 int64_t finval;
437
438 if (!tuner_awake())
439 return 0;
440
441 /* enable measuring */
442 tuner_sanyo_write_or(MSRC_SEL, type);
443 tuner_sanyo_write_and(CNT_CTRL, ~CNT_SEL);
444 tuner_sanyo_write_or(RADIO_CTRL1, EN_MEAS);
445
446 /* reset counter */
447 tuner_sanyo_write_or(CNT_CTRL, CNT1_CLR);
448 tuner_sanyo_write_and(CNT_CTRL, ~CNT1_CLR);
449
450 /* start counter, delay for specified time and stop it */
451 tuner_sanyo_write_or(CNT_CTRL, CNT_EN);
452 udelay(duration*1000 - 16);
453 tuner_sanyo_write_and(CNT_CTRL, ~CNT_EN);
454
455 /* read tick count */
456 finval = (tuner_sanyo_read(CNT_H) << 8) | tuner_sanyo_read(CNT_L);
457
458 /* restore measure mode */
459 tuner_sanyo_write_and(RADIO_CTRL1, ~EN_MEAS);
460 tuner_sanyo_write_and(MSRC_SEL, ~type);
461
462 /* convert value */
463 if (type == MSS_FM)
464 finval = scale*finval*256 / duration;
465 else
466 finval = scale*finval / duration;
467
468 return (int)finval;
469}
470
471/* set the FM oscillator frequency */
472static void sanyo_set_frequency(int freq)
473{
474 int coef, cap_value, osc_value;
475 int f1, f2, x1, x2;
476 int count;
477
478 if (!tuner_awake())
479 return;
480
481 TUNER_LOG_OPEN();
482
483 TUNER_LOG("set_frequency(%d)\n", freq);
484
485 enable_afc(false);
486
487 /* MHz -> kHz */
488 freq /= 1000;
489
490 TUNER_LOG("Select cap:\n");
491
492 coef = calculate_coef(freq);
493 cap_value = interpolate_x(coef, sw_cap_low, sw_cap_high,
494 coef_00, coef_01);
495
496 osc_value = sw_osc_low;
497 tuner_sanyo_write(FM_OSC, osc_value);
498
499 /* Just in case - don't go into infinite loop */
500 for (count = 0; count < 30; count++)
501 {
502 int y0 = interpolate_y(cap_value, sw_cap_low, sw_cap_high,
503 coef_00, coef_01);
504 int y1 = interpolate_y(cap_value, sw_cap_low, sw_cap_high,
505 coef_10, coef_11);
506 int coef_fcur, cap_new, coef_cor, range;
507
508 tuner_sanyo_write(FM_CAP, cap_value);
509
510 range = y1 - y0;
511 f1 = tuner_measure(MSS_FM, 1, 16);
512 coef_fcur = calculate_coef(f1);
513 coef_cor = calculate_coef((f1*1000 + 32*256) / 1000);
514 y0 = coef_cor;
515 y1 = y0 + range;
516
517 TUNER_LOG("%d %d %d %d %d %d %d %d\n",
518 f1, cap_value, coef, coef_fcur, coef_cor, y0, y1, range);
519
520 if (coef >= y0 && coef <= y1)
521 {
522 osc_value = interpolate_x(coef, sw_osc_low, sw_osc_high,
523 y0, y1);
524
525 if (osc_value >= sw_osc_low && osc_value <= sw_osc_high)
526 break;
527 }
528
529 cap_new = interpolate_x(coef, cap_value, sw_cap_high,
530 coef_fcur, coef_01);
531
532 if (cap_new == cap_value)
533 {
534 if (coef < coef_fcur)
535 cap_value++;
536 else
537 cap_value--;
538 }
539 else
540 {
541 cap_value = cap_new;
542 }
543 }
544
545 TUNER_LOG("osc_value: %d\n", osc_value);
546
547 TUNER_LOG("Tune:\n");
548
549 x1 = sw_osc_low, x2 = sw_osc_high;
550 /* FM_OSC already at SW_OSC low and f1 is already the measured
551 frequency */
552
553 do
554 {
555 int x2_new;
556
557 tuner_sanyo_write(FM_OSC, x2);
558 f2 = tuner_measure(MSS_FM, 1, 16);
559
560 if (abs(f2 - freq) <= 16)
561 {
562 TUNER_LOG("%d %d %d %d\n", f1, f2, x1, x2);
563 break;
564 }
565
566 x2_new = interpolate_x(freq, x1, x2, f1, f2);
567
568 x1 = x2, f1 = f2, x2 = x2_new;
569 TUNER_LOG("%d %d %d %d\n", f1, f2, x1, x2);
570 }
571 while (x2 != 0);
572
573 if (x2 == 0)
574 {
575 /* May still be close enough */
576 TUNER_LOG("tuning failed - diff: %d\n", f2 - freq);
577 }
578
579 enable_afc(true);
580
581 TUNER_LOG("\n");
582
583 TUNER_LOG_SYNC();
584}
585
586static void fine_step_tune(int (*setcmp)(int regval), int regval, int step)
587{
588 /* Registers are not always stable, timeout if best fit not found soon
589 enough */
590 unsigned long abort = current_tick + HZ*2;
591 int flags = 0;
592
593 while (TIME_BEFORE(current_tick, abort))
594 {
595 int cmp;
596
597 regval = regval + step;
598
599 cmp = setcmp(regval);
600
601 if (cmp == 0)
602 break;
603
604 step = abs(step);
605
606 if (cmp < 0)
607 {
608 flags |= 1;
609 if (step == 1)
610 flags |= 4;
611 }
612 else
613 {
614 step = -step;
615 flags |= 2;
616 if (step == -1)
617 step |= 8;
618 }
619
620 if ((flags & 0xc) == 0xc)
621 break;
622
623 if ((flags & 0x3) == 0x3)
624 {
625 step /= 2;
626 if (step == 0)
627 step = 1;
628 flags &= ~3;
629 }
630 }
631}
632
633static int if_setcmp(int regval)
634{
635 tuner_sanyo_write(IF_OSC, regval);
636 tuner_sanyo_write(IF_CENTER, regval);
637 tuner_sanyo_write(IF_BW, 65*regval/100);
638
639 if_set = tuner_measure(MSS_IF, 1000, 32);
640
641 /* This register is bounces around by a few hundred Hz and doesn't seem
642 to be precisely tuneable. Just do 110000 +/- 500 since it's not very
643 critical it seems. */
644 if (abs(if_set - 109500) <= 500)
645 return 0;
646
647 return if_set < 109500 ? -1 : 1;
648}
649
650static int sd_setcmp(int regval)
651{
652 tuner_sanyo_write(SD_OSC, regval);
653
654 sd_set = tuner_measure(MSS_SD, 1000, 32);
655
656 if (abs(sd_set - 38300) <= 31)
657 return 0;
658
659 return sd_set < 38300 ? -1 : 1;
660}
661
662static void sanyo_sleep(bool sleep)
663{
664 if (sleep || tuner_awake())
665 return;
666
667 if ((tuner_status & (TUNER_PRESENT | TUNER_POWERED)) !=
668 (TUNER_PRESENT | TUNER_POWERED))
669 return;
670
671 tuner_status |= TUNER_AWAKE;
672
673 enable_afc(false);
674
675 /* 2. Calibrate the IF frequency at 110 kHz: */
676 tuner_sanyo_write_and(RADIO_CTRL2, ~IF_PM_L);
677 fine_step_tune(if_setcmp, 0x80, 8);
678 tuner_sanyo_write_or(RADIO_CTRL2, IF_PM_L);
679
680 /* 3. Calibrate the stereo decoder clock at 38.3 kHz: */
681 tuner_sanyo_write_or(STEREO_CTRL, SD_PM);
682 fine_step_tune(sd_setcmp, 0x80, 8);
683 tuner_sanyo_write_and(STEREO_CTRL, ~SD_PM);
684
685 /* calculate FM tuning coefficients */
686 tuner_sanyo_write(FM_CAP, sw_cap_low);
687 tuner_sanyo_write(FM_OSC, sw_osc_low);
688 coef_00 = calculate_coef(tuner_measure(MSS_FM, 1, 64));
689
690 tuner_sanyo_write(FM_CAP, sw_cap_high);
691 coef_01 = calculate_coef(tuner_measure(MSS_FM, 1, 64));
692
693 tuner_sanyo_write(FM_CAP, sw_cap_low);
694 tuner_sanyo_write(FM_OSC, sw_osc_high);
695 coef_10 = calculate_coef(tuner_measure(MSS_FM, 1, 64));
696
697 tuner_sanyo_write(FM_CAP, sw_cap_high);
698 coef_11 = calculate_coef(tuner_measure(MSS_FM, 1, 64));
699
700 /* set various audio level settings */
701 tuner_sanyo_write(AUDIO_CTRL1, TONE_LVL_SET(0) | VOL_LVL_SET(0));
702 tuner_sanyo_write_or(RADIO_CTRL2, AGCSP);
703 tuner_sanyo_write_or(RADIO_CTRL3, VOLSH);
704 tuner_sanyo_write(STEREO_CTRL, FMCS_SET(7) | AUTOSSR);
705 tuner_sanyo_write(PW_SCTRL, SS_CTRL_SET(3) | SM_CTRL_SET(1) |
706 PW_RAD);
707}
708
709/** Public interfaces **/
710bool radio_power(bool status)
711{
712 static const unsigned char tuner_defaults[][2] =
713 {
714 /* Block 1 writeable registers */
715 { MSRC_SEL, AFC_LVL },
716 { FM_OSC, 0x80 },
717 { SD_OSC, 0x80 },
718 { IF_OSC, 0x80 },
719 { CNT_CTRL, CNT1_CLR | SWP_CNT_L },
720 { IRQ_MSK, 0x00 }, /* IRQ_LVL -> Low to High */
721 { FM_CAP, 0x80 },
722 /* { IRQ_OUT, 0x00 }, No action on this register (skip) */
723 /* Block 2 writeable registers */
724 { RADIO_CTRL1, EN_AFC },
725 { IF_CENTER, 0x80 },
726 { IF_BW, 65*0x80 / 100 }, /* 65% of IF_OSC */
727 { RADIO_CTRL2, IF_PM_L },
728 { RADIO_CTRL3, AGC_SLVL | SE_FM },
729 { STEREO_CTRL, FMCS_SET(4) | AUTOSSR },
730 { AUDIO_CTRL1, TONE_LVL_SET(7) | VOL_LVL_SET(7) },
731 { AUDIO_CTRL2, BPFREQ_HIGH }, /* deemphasis 50us */
732 { PW_SCTRL, SS_CTRL_SET(3) | SM_CTRL_SET(3) | PW_RAD },
733 };
734
735 unsigned i;
736 bool powered = tuner_status & TUNER_POWERED;
737
738 if (status == powered)
739 return powered;
740
741 if (status)
742 {
743 /* init mystery amplification device */
744 outl(inl(0x70000084) | 0x1, 0x70000084);
745 outl(inl(0x70000080) | 0x4, 0x70000080);
746 udelay(5);
747
748 /* When power up, host should initialize the 3-wire bus in host read
749 mode: */
750
751 /* 1. Set direction of the DATA-line to input-mode. */
752 GPIOH_OUTPUT_EN &= ~(1 << FM_DATA_PIN);
753 GPIOH_ENABLE |= (1 << FM_DATA_PIN);
754
755 /* 2. Drive NR_W low */
756 GPIOH_OUTPUT_VAL &= ~(1 << FM_NRW_PIN);
757 GPIOH_OUTPUT_EN |= (1 << FM_NRW_PIN);
758 GPIOH_ENABLE |= (1 << FM_NRW_PIN);
759
760 /* 3. Drive CLOCK high */
761 GPIOH_OUTPUT_VAL |= (1 << FM_CLOCK_PIN);
762 GPIOH_OUTPUT_EN |= (1 << FM_CLOCK_PIN);
763 GPIOH_ENABLE |= (1 << FM_CLOCK_PIN);
764
765 tuner_status |= TUNER_POWERED;
766
767 /* if tuner is present, CHIP ID is 0x09 */
768 if (tuner_sanyo_read(CHIP_ID) == 0x09)
769 {
770 tuner_status |= TUNER_PRESENT;
771
772 /* After power-up, the LV2400x needs to be initialized as
773 follows: */
774
775 /* 1. Write default values to the registers: */
776 sanyo_regs[BLK_SEL] = 0; /* Force a switch on the first */
777 for (i = 0; i < ARRAYLEN(tuner_defaults); i++)
778 tuner_sanyo_write(tuner_defaults[i][0], tuner_defaults[i][1]);
779
780 /* Complete the startup calibration if the tuner is woken */
781 udelay(100000);
782 }
783 }
784 else
785 {
786 /* Power off and set all as inputs */
787 if (tuner_status & TUNER_PRESENT)
788 tuner_sanyo_write_and(PW_SCTRL, ~PW_RAD);
789
790 GPIOH_OUTPUT_EN &= ~((1 << FM_DATA_PIN) | (1 << FM_NRW_PIN) |
791 (1 << FM_CLOCK_PIN));
792 GPIOH_ENABLE &= ~((1 << FM_DATA_PIN) | (1 << FM_NRW_PIN) |
793 (1 << FM_CLOCK_PIN));
794
795 outl(inl(0x70000084) & ~0x1, 0x70000084);
796
797 tuner_status &= ~(TUNER_POWERED | TUNER_AWAKE);
798 }
799
800 return powered;
801}
802
803bool radio_powered(void)
804{
805 return (tuner_status & TUNER_POWERED) != 0;
806}
807
808int sanyo_set(int setting, int value)
809{
810 int val = 1;
811
812 switch(setting)
813 {
814 case RADIO_SLEEP:
815 sanyo_sleep(value);
816 break;
817
818 case RADIO_FREQUENCY:
819 sanyo_set_frequency(value);
820 break;
821
822 case RADIO_SCAN_FREQUENCY:
823 /* TODO: really implement this */
824 sanyo_set_frequency(value);
825 val = sanyo_get(RADIO_TUNED);
826 break;
827
828 case RADIO_MUTE:
829 if (value)
830 tuner_sanyo_write_and(RADIO_CTRL3, ~AMUTE_L);
831 else
832 tuner_sanyo_write_or(RADIO_CTRL3, AMUTE_L);
833 break;
834
835 case RADIO_REGION:
836 switch (value)
837 {
838 case REGION_EUROPE:
839 case REGION_JAPAN:
840 case REGION_KOREA:
841 tuner_sanyo_write_and(AUDIO_CTRL2, ~DEEMP);
842 break;
843 case REGION_US_CANADA:
844 tuner_sanyo_write_or(AUDIO_CTRL2, DEEMP);
845 break;
846 default:
847 val = -1;
848 }
849 break;
850
851 case RADIO_FORCE_MONO:
852 if (value)
853 tuner_sanyo_write_or(STEREO_CTRL, ST_M);
854 else
855 tuner_sanyo_write_and(STEREO_CTRL, ~ST_M);
856 break;
857
858 default:
859 val = -1;
860 }
861
862 return val;
863}
864
865int sanyo_get(int setting)
866{
867 int val = -1;
868
869 switch(setting)
870 {
871 case RADIO_ALL:
872 return tuner_sanyo_read(CTRL_STAT);
873
874 case RADIO_TUNED:
875 /* TODO: really implement this */
876 val = RSS_FS(tuner_sanyo_read(RADIO_STAT)) < 0x1f;
877 break;
878
879 case RADIO_STEREO:
880 val = (tuner_sanyo_read(RADIO_STAT) & RSS_MS) != 0;
881 break;
882
883 case RADIO_PRESENT:
884 val = (tuner_status & TUNER_PRESENT) != 0;
885 break;
886
887 /* tuner-specific debug info */
888 case RADIO_REG_STAT:
889 return tuner_sanyo_read(RADIO_STAT);
890
891 case RADIO_MSS_FM:
892 return tuner_measure(MSS_FM, 1, 16);
893
894 case RADIO_MSS_IF:
895 return tuner_measure(MSS_IF, 1000, 16);
896
897 case RADIO_MSS_SD:
898 return tuner_measure(MSS_SD, 1000, 16);
899
900 case RADIO_IF_SET:
901 return if_set;
902
903 case RADIO_SD_SET:
904 return sd_set;
905 }
906
907 return val;
908}
909#endif /* BOOTLOADER */