1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
9 * Tuner driver for the Sanyo LV24020LP
11 * Copyright (C) 2007 Ivan Zupan
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.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
26 #include "tuner.h" /* tuner abstraction interface */
27 #include "fmradio.h" /* physical interface driver */
37 /* define to enable tuner logging */
38 #define SANYO_TUNER_LOG
41 #ifdef SANYO_TUNER_LOG
45 static int fd_log
= -1;
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)
53 #define TUNER_LOG_OPEN()
54 #define TUNER_LOG_SYNC()
55 #define TUNER_LOG(s...)
56 #endif /* SANYO_TUNER_LOG */
58 /** tuner register defines **/
60 /* pins on GPIOH port */
62 #define FM_CLOCK_PIN 4
64 #define FM_CLK_DELAY 1
66 /* block 1 registers */
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)
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)
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)
123 #define CNT_L 0x0a /* Counter register low value */
126 #define CNT_H 0x0b /* Counter register high value */
129 #define CTRL_STAT 0x0c
130 #define AFC_FLG (1 << 0)
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. */
142 #define II_CNT2 (1 << 5)
143 #define II_AFC (1 << 3)
144 #define II_FS_MS (1 << 0)
149 /* block 2 registers - offset added in order to id and avoid manual
151 #define BLK2_START 0x10
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)
161 #define IF_CENTER (0x03 + BLK2_START)
164 #define IF_BW (0x05 + BLK2_START)
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) /* ?? */
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. */
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)
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)
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)
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)
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)
235 static unsigned tuner_status
= 0;
237 static unsigned char sanyo_regs
[0x1c];
239 static const int sw_osc_low
= 10; /* 30; */
240 static const int sw_osc_high
= 240; /* 200; */
241 static const int sw_cap_low
= 0;
242 static const int sw_cap_high
= 191;
244 /* linear coefficients used for tuning */
245 static int coef_00
, coef_01
, coef_10
, coef_11
;
247 /* DAC control register set values */
250 static inline bool tuner_awake(void)
252 return (tuner_status
& TUNER_AWAKE
) != 0;
255 /* send a byte to the tuner - expects write mode to be current */
256 static void tuner_sanyo_send_byte(unsigned int byte
)
260 byte
<<= FM_DATA_PIN
;
262 for (i
= 0; i
< 8; i
++)
264 GPIOH_OUTPUT_VAL
&= ~(1 << FM_CLOCK_PIN
);
266 GPIOH_OUTPUT_VAL
= (GPIOH_OUTPUT_VAL
& ~(1 << FM_DATA_PIN
)) |
267 (byte
& (1 << FM_DATA_PIN
));
269 GPIOH_OUTPUT_VAL
|= (1 << FM_CLOCK_PIN
);
270 udelay(FM_CLK_DELAY
);
276 /* end a write cycle on the tuner */
277 static void tuner_sanyo_end_write(void)
279 /* switch back to read mode */
280 GPIOH_OUTPUT_EN
&= ~(1 << FM_DATA_PIN
);
281 GPIOH_OUTPUT_VAL
&= ~(1 << FM_NRW_PIN
);
284 /* prepare a write cycle on the tuner */
285 static unsigned int tuner_sanyo_begin_write(unsigned int address
)
287 /* Get register's block, translate address */
288 unsigned int blk
= (address
>= BLK2_START
) ?
289 (address
-= BLK2_START
, BLK2
) : BLK1
;
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
);
297 udelay(FM_CLK_DELAY
);
299 /* current block == register block? */
300 if (blk
== sanyo_regs
[BLK_SEL
])
304 sanyo_regs
[BLK_SEL
] = blk
;
307 tuner_sanyo_send_byte(blk
);
309 tuner_sanyo_send_byte(BLK_SEL
);
311 tuner_sanyo_end_write();
313 udelay(FM_CLK_DELAY
);
317 /* write a byte to a tuner register */
318 static void tuner_sanyo_write(unsigned int address
, unsigned int data
)
320 /* shadow logical values but do logical=>physical remappings on some
322 sanyo_regs
[address
] = data
;
332 /* L: 000..063, 064..191
333 * P: 255..192, 127..000 */
334 data
= ((data
< 64) ? 255 : (255 - 64)) - data
;
338 * P: data | always "1" bits */
339 data
|= (1 << 4) | (1 << 1) | (1 << 0);
343 address
= tuner_sanyo_begin_write(address
);
346 tuner_sanyo_send_byte(data
);
348 tuner_sanyo_send_byte(address
);
350 tuner_sanyo_end_write();
353 /* helpers to set/clear register bits */
354 static void tuner_sanyo_write_or(unsigned int address
, unsigned int bits
)
356 tuner_sanyo_write(address
, sanyo_regs
[address
] | bits
);
359 static void tuner_sanyo_write_and(unsigned int address
, unsigned int bits
)
361 tuner_sanyo_write(address
, sanyo_regs
[address
] & bits
);
364 /* read a byte from a tuner register */
365 static unsigned int tuner_sanyo_read(unsigned int address
)
370 address
= tuner_sanyo_begin_write(address
);
373 tuner_sanyo_send_byte(address
);
375 tuner_sanyo_end_write();
379 for (i
= 0; i
< 8; i
++)
381 GPIOH_OUTPUT_VAL
&= ~(1 << FM_CLOCK_PIN
);
382 udelay(FM_CLK_DELAY
);
384 toread
|= (GPIOH_INPUT_VAL
& (1 << FM_DATA_PIN
)) << i
;
386 GPIOH_OUTPUT_VAL
|= (1 << FM_CLOCK_PIN
);
389 return toread
>> FM_DATA_PIN
;
392 /* enables auto frequency centering */
393 static void enable_afc(bool enabled
)
395 unsigned int radio_ctrl1
= sanyo_regs
[RADIO_CTRL1
];
399 radio_ctrl1
&= ~RST_AFC
;
400 radio_ctrl1
|= EN_AFC
;
404 radio_ctrl1
|= RST_AFC
;
405 radio_ctrl1
&= ~EN_AFC
;
408 tuner_sanyo_write(RADIO_CTRL1
, radio_ctrl1
);
411 static int calculate_coef(unsigned fkhz
)
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
);
420 static int interpolate_x(int expected_y
, int x1
, int x2
, int y1
, int y2
)
423 0 : (int64_t)(expected_y
- y1
)*(x2
- x1
) / (y2
- y1
) + x1
;
426 static int interpolate_y(int expected_x
, int x1
, int x2
, int y1
, int y2
)
429 0 : (int64_t)(expected_x
- x1
)*(y2
- y1
) / (x2
- x1
) + y1
;
432 /* this performs measurements of IF, FM and Stereo frequencies
433 * Input can be: MSS_FM, MSS_IF, MSS_SD */
434 static int tuner_measure(unsigned char type
, int scale
, int duration
)
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
);
447 tuner_sanyo_write_or(CNT_CTRL
, CNT1_CLR
);
448 tuner_sanyo_write_and(CNT_CTRL
, ~CNT1_CLR
);
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
);
455 /* read tick count */
456 finval
= (tuner_sanyo_read(CNT_H
) << 8) | tuner_sanyo_read(CNT_L
);
458 /* restore measure mode */
459 tuner_sanyo_write_and(RADIO_CTRL1
, ~EN_MEAS
);
460 tuner_sanyo_write_and(MSRC_SEL
, ~type
);
464 finval
= scale
*finval
*256 / duration
;
466 finval
= scale
*finval
/ duration
;
471 /* set the FM oscillator frequency */
472 static void sanyo_set_frequency(int freq
)
474 int coef
, cap_value
, osc_value
;
483 TUNER_LOG("set_frequency(%d)\n", freq
);
490 TUNER_LOG("Select cap:\n");
492 coef
= calculate_coef(freq
);
493 cap_value
= interpolate_x(coef
, sw_cap_low
, sw_cap_high
,
496 osc_value
= sw_osc_low
;
497 tuner_sanyo_write(FM_OSC
, osc_value
);
499 /* Just in case - don't go into infinite loop */
500 for (count
= 0; count
< 30; count
++)
502 int y0
= interpolate_y(cap_value
, sw_cap_low
, sw_cap_high
,
504 int y1
= interpolate_y(cap_value
, sw_cap_low
, sw_cap_high
,
506 int coef_fcur
, cap_new
, coef_cor
, range
;
508 tuner_sanyo_write(FM_CAP
, cap_value
);
511 f1
= tuner_measure(MSS_FM
, 1, 16);
512 coef_fcur
= calculate_coef(f1
);
513 coef_cor
= calculate_coef((f1
*1000 + 32*256) / 1000);
517 TUNER_LOG("%d %d %d %d %d %d %d %d\n",
518 f1
, cap_value
, coef
, coef_fcur
, coef_cor
, y0
, y1
, range
);
520 if (coef
>= y0
&& coef
<= y1
)
522 osc_value
= interpolate_x(coef
, sw_osc_low
, sw_osc_high
,
525 if (osc_value
>= sw_osc_low
&& osc_value
<= sw_osc_high
)
529 cap_new
= interpolate_x(coef
, cap_value
, sw_cap_high
,
532 if (cap_new
== cap_value
)
534 if (coef
< coef_fcur
)
545 TUNER_LOG("osc_value: %d\n", osc_value
);
547 TUNER_LOG("Tune:\n");
549 x1
= sw_osc_low
, x2
= sw_osc_high
;
550 /* FM_OSC already at SW_OSC low and f1 is already the measured
557 tuner_sanyo_write(FM_OSC
, x2
);
558 f2
= tuner_measure(MSS_FM
, 1, 16);
560 if (abs(f2
- freq
) <= 16)
562 TUNER_LOG("%d %d %d %d\n", f1
, f2
, x1
, x2
);
566 x2_new
= interpolate_x(freq
, x1
, x2
, f1
, f2
);
568 x1
= x2
, f1
= f2
, x2
= x2_new
;
569 TUNER_LOG("%d %d %d %d\n", f1
, f2
, x1
, x2
);
575 /* May still be close enough */
576 TUNER_LOG("tuning failed - diff: %d\n", f2
- freq
);
586 static void fine_step_tune(int (*setcmp
)(int regval
), int regval
, int step
)
588 /* Registers are not always stable, timeout if best fit not found soon
590 unsigned long abort
= current_tick
+ HZ
*2;
593 while (TIME_BEFORE(current_tick
, abort
))
597 regval
= regval
+ step
;
599 cmp
= setcmp(regval
);
620 if ((flags
& 0xc) == 0xc)
623 if ((flags
& 0x3) == 0x3)
633 static int if_setcmp(int regval
)
635 tuner_sanyo_write(IF_OSC
, regval
);
636 tuner_sanyo_write(IF_CENTER
, regval
);
637 tuner_sanyo_write(IF_BW
, 65*regval
/100);
639 if_set
= tuner_measure(MSS_IF
, 1000, 32);
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)
647 return if_set
< 109500 ? -1 : 1;
650 static int sd_setcmp(int regval
)
652 tuner_sanyo_write(SD_OSC
, regval
);
654 sd_set
= tuner_measure(MSS_SD
, 1000, 32);
656 if (abs(sd_set
- 38300) <= 31)
659 return sd_set
< 38300 ? -1 : 1;
662 static void sanyo_sleep(bool sleep
)
664 if (sleep
|| tuner_awake())
667 if ((tuner_status
& (TUNER_PRESENT
| TUNER_POWERED
)) !=
668 (TUNER_PRESENT
| TUNER_POWERED
))
671 tuner_status
|= TUNER_AWAKE
;
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
);
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
);
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));
690 tuner_sanyo_write(FM_CAP
, sw_cap_high
);
691 coef_01
= calculate_coef(tuner_measure(MSS_FM
, 1, 64));
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));
697 tuner_sanyo_write(FM_CAP
, sw_cap_high
);
698 coef_11
= calculate_coef(tuner_measure(MSS_FM
, 1, 64));
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) |
709 /** Public interfaces **/
710 bool radio_power(bool status
)
712 static const unsigned char tuner_defaults
[][2] =
714 /* Block 1 writeable registers */
715 { MSRC_SEL
, AFC_LVL
},
719 { CNT_CTRL
, CNT1_CLR
| SWP_CNT_L
},
720 { IRQ_MSK
, 0x00 }, /* IRQ_LVL -> Low to High */
722 /* { IRQ_OUT, 0x00 }, No action on this register (skip) */
723 /* Block 2 writeable registers */
724 { RADIO_CTRL1
, EN_AFC
},
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
},
736 bool powered
= tuner_status
& TUNER_POWERED
;
738 if (status
== powered
)
743 /* init mystery amplification device */
744 outl(inl(0x70000084) | 0x1, 0x70000084);
747 /* When power up, host should initialize the 3-wire bus in host read
750 /* 1. Set direction of the DATA-line to input-mode. */
751 GPIOH_OUTPUT_EN
&= ~(1 << FM_DATA_PIN
);
752 GPIOH_ENABLE
|= (1 << FM_DATA_PIN
);
754 /* 2. Drive NR_W low */
755 GPIOH_OUTPUT_VAL
&= ~(1 << FM_NRW_PIN
);
756 GPIOH_OUTPUT_EN
|= (1 << FM_NRW_PIN
);
757 GPIOH_ENABLE
|= (1 << FM_NRW_PIN
);
759 /* 3. Drive CLOCK high */
760 GPIOH_OUTPUT_VAL
|= (1 << FM_CLOCK_PIN
);
761 GPIOH_OUTPUT_EN
|= (1 << FM_CLOCK_PIN
);
762 GPIOH_ENABLE
|= (1 << FM_CLOCK_PIN
);
764 tuner_status
|= TUNER_POWERED
;
766 /* if tuner is present, CHIP ID is 0x09 */
767 if (tuner_sanyo_read(CHIP_ID
) == 0x09)
769 tuner_status
|= TUNER_PRESENT
;
771 /* After power-up, the LV2400x needs to be initialized as
774 /* 1. Write default values to the registers: */
775 sanyo_regs
[BLK_SEL
] = 0; /* Force a switch on the first */
776 for (i
= 0; i
< ARRAYLEN(tuner_defaults
); i
++)
777 tuner_sanyo_write(tuner_defaults
[i
][0], tuner_defaults
[i
][1]);
779 /* Complete the startup calibration if the tuner is woken */
785 /* Power off and set all as inputs */
786 if (tuner_status
& TUNER_PRESENT
)
787 tuner_sanyo_write_and(PW_SCTRL
, ~PW_RAD
);
789 GPIOH_OUTPUT_EN
&= ~((1 << FM_DATA_PIN
) | (1 << FM_NRW_PIN
) |
790 (1 << FM_CLOCK_PIN
));
791 GPIOH_ENABLE
&= ~((1 << FM_DATA_PIN
) | (1 << FM_NRW_PIN
) |
792 (1 << FM_CLOCK_PIN
));
794 outl(inl(0x70000084) & ~0x1, 0x70000084);
796 tuner_status
&= ~(TUNER_POWERED
| TUNER_AWAKE
);
802 bool radio_powered(void)
804 return (tuner_status
& TUNER_POWERED
) != 0;
807 int sanyo_set(int setting
, int value
)
817 case RADIO_FREQUENCY
:
818 sanyo_set_frequency(value
);
821 case RADIO_SCAN_FREQUENCY
:
822 /* TODO: really implement this */
823 sanyo_set_frequency(value
);
824 val
= sanyo_get(RADIO_TUNED
);
829 tuner_sanyo_write_and(RADIO_CTRL3
, ~AMUTE_L
);
831 tuner_sanyo_write_or(RADIO_CTRL3
, AMUTE_L
);
840 tuner_sanyo_write_and(AUDIO_CTRL2
, ~DEEMP
);
842 case REGION_US_CANADA
:
843 tuner_sanyo_write_or(AUDIO_CTRL2
, DEEMP
);
850 case RADIO_FORCE_MONO
:
852 tuner_sanyo_write_or(STEREO_CTRL
, ST_M
);
854 tuner_sanyo_write_and(STEREO_CTRL
, ~ST_M
);
864 int sanyo_get(int setting
)
871 return tuner_sanyo_read(CTRL_STAT
);
874 /* TODO: really implement this */
875 val
= RSS_FS(tuner_sanyo_read(RADIO_STAT
)) < 0x1f;
879 val
= (tuner_sanyo_read(RADIO_STAT
) & RSS_MS
) != 0;
883 val
= (tuner_status
& TUNER_PRESENT
) != 0;
886 /* tuner-specific debug info */
888 return tuner_sanyo_read(RADIO_STAT
);
891 return tuner_measure(MSS_FM
, 1, 16);
894 return tuner_measure(MSS_IF
, 1000, 16);
897 return tuner_measure(MSS_SD
, 1000, 16);
908 #endif /* BOOTLOADER */