1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
9 * Tuner driver for the Sanyo LV24020LP
11 * Copyright (C) 2007 Ivan Zupan
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
28 #include "tuner.h" /* tuner abstraction interface */
30 #include "fmradio.h" /* physical interface driver */
36 static struct mutex tuner_mtx
;
38 /* define RSSI range */
42 /* define to enable tuner logging */
43 #undef SANYO_TUNER_LOG_FILE
44 #undef SANYO_TUNER_LOGF
46 #ifdef SANYO_TUNER_LOG_FILE
49 static int fd_log
= -1;
51 #define TUNER_LOG_OPEN() if (fd_log < 0) \
52 fd_log = creat("/tuner_dump.txt", 0666)
53 /* syncing required because close() is never called */
54 #define TUNER_LOG_SYNC() fsync(fd_log)
55 #define TUNER_LOG(s...) fdprintf(fd_log, s)
57 #elif defined(SANYO_TUNER_LOGF)
58 /*#define LOGF_ENABLE*/
61 #define TUNER_LOG_OPEN()
62 #define TUNER_LOG_SYNC()
63 #define TUNER_LOG(s...) logf(s)
66 #define TUNER_LOG_OPEN()
67 #define TUNER_LOG_SYNC()
68 #define TUNER_LOG(s...)
69 #endif /* SANYO_TUNER_LOG */
71 /** tuner register defines **/
73 #if defined(SANSA_E200) || defined(SANSA_C200)
74 #define TUNER_GPIO_INPUT_VAL GPIOH_INPUT_VAL
75 #define TUNER_GPIO_OUTPUT_EN_SET(mask) GPIO_SET_BITWISE(GPIOH_OUTPUT_EN, mask)
76 #define TUNER_GPIO_OUTPUT_EN_CLEAR(mask) GPIO_CLEAR_BITWISE(GPIOH_OUTPUT_EN, mask)
77 #define TUNER_GPIO_OUTPUT_VAL_SET(mask) GPIO_SET_BITWISE(GPIOH_OUTPUT_VAL, mask)
78 #define TUNER_GPIO_OUTPUT_VAL_CLEAR(mask) GPIO_CLEAR_BITWISE(GPIOH_OUTPUT_VAL, mask)
80 #define FM_CLOCK_PIN 4
83 #elif defined(IAUDIO_7)
84 #define TUNER_GPIO_INPUT_VAL GPIOA
85 #define TUNER_GPIO_OUTPUT_EN_SET(mask) (GPIOA_DIR |= (mask))
86 #define TUNER_GPIO_OUTPUT_EN_CLEAR(mask) (GPIOA_DIR &= ~(mask))
87 #define TUNER_GPIO_OUTPUT_VAL_SET(mask) (GPIOA |= (mask))
88 #define TUNER_GPIO_OUTPUT_VAL_CLEAR(mask) (GPIOA &= ~(mask))
89 #define FM_CLOCK_PIN 5
93 #elif defined(COWON_D2)
94 #define TUNER_GPIO_INPUT_VAL GPIOC
95 #define TUNER_GPIO_OUTPUT_EN_SET(mask) (GPIOC_DIR |= (mask))
96 #define TUNER_GPIO_OUTPUT_EN_CLEAR(mask) (GPIOC_DIR &= ~(mask))
97 #define TUNER_GPIO_OUTPUT_VAL_SET(mask) (GPIOC |= (mask))
98 #define TUNER_GPIO_OUTPUT_VAL_CLEAR(mask) (GPIOC &= ~(mask))
100 #define FM_CLOCK_PIN 29
101 #define FM_DATA_PIN 30
104 #error GPIOs undefined for this target
107 #define FM_CLK_DELAY 1
109 /* block 1 registers */
120 #define MSRC_SEL 0x02
121 #define MSR_O (1 << 7)
122 #define AFC_LVL (1 << 6)
123 #define AFC_SPD (1 << 5)
124 #define MSS_SD (1 << 2)
125 #define MSS_FM (1 << 1)
126 #define MSS_IF (1 << 0)
138 #define CNT_CTRL 0x06
139 #define CNT1_CLR (1 << 7)
140 #define CTAB(x) ((x) & (0x7 << 4))
141 #define CTAB_STOP_2 (0x0 << 4)
142 #define CTAB_STOP_8 (0x1 << 4)
143 #define CTAB_STOP_32 (0x2 << 4)
144 #define CTAB_STOP_128 (0x3 << 4)
145 #define CTAB_STOP_512 (0x4 << 4)
146 #define CTAB_STOP_2048 (0x5 << 4)
147 #define CTAB_STOP_8192 (0x6 << 4)
148 #define CTAB_STOP_32768 (0x7 << 4)
149 #define SWP_CNT_L (1 << 3)
150 #define CNT_EN (1 << 2)
151 #define CNT_SEL (1 << 1)
152 #define CNT_SET (1 << 0)
156 #define IM_MS (1 << 6)
157 #define IRQ_LVL (1 << 3)
158 #define IM_AFC (1 << 2)
159 #define IM_FS (1 << 1)
160 #define IM_CNT2 (1 << 0)
166 #define CNT_L 0x0a /* Counter register low value */
169 #define CNT_H 0x0b /* Counter register high value */
172 #define CTRL_STAT 0x0c
173 #define AFC_FLG (1 << 0)
176 #define RADIO_STAT 0x0d
177 #define RSS_MS (1 << 7)
178 #define RSS_FS(x) ((x) & 0x7f)
179 #define RSS_FS_GET(x) ((x) & 0x7f)
180 #define RSS_FS_SET(x) (x)
181 /* Note: Reading this register will clear field strength and mono/stereo interrupt. */
185 #define II_CNT2 (1 << 5)
186 #define II_AFC (1 << 3)
187 #define II_FS_MS (1 << 0)
192 /* block 2 registers - offset added in order to id and avoid manual
194 #define BLK2_START 0x10
197 #define RADIO_CTRL1 (0x02 + BLK2_START)
198 #define EN_MEAS (1 << 7)
199 #define EN_AFC (1 << 6)
200 #define DIR_AFC (1 << 3)
201 #define RST_AFC (1 << 2)
204 #define IF_CENTER (0x03 + BLK2_START)
207 #define IF_BW (0x05 + BLK2_START)
210 #define RADIO_CTRL2 (0x06 + BLK2_START)
211 #define VREF2 (1 << 7)
212 #define VREF (1 << 6)
213 #define STABI_BP (1 << 5)
214 #define IF_PM_L (1 << 4)
215 #define AGCSP (1 << 1)
216 #define AM_ANT_BSW (1 << 0) /* ?? */
219 #define RADIO_CTRL3 (0x07 + BLK2_START)
220 #define AGC_SLVL (1 << 7)
221 #define VOLSH (1 << 6)
222 #define TB_ON (1 << 5)
223 #define AMUTE_L (1 << 4)
224 #define SE_FM (1 << 3)
225 #define SE_BE (1 << 1)
226 #define SE_EXT (1 << 0) /* For LV24000=0, LV24001/24002=Ext source enab. */
229 #define STEREO_CTRL (0x08 + BLK2_START)
230 #define FRCST (1 << 7)
231 #define FMCS(x) ((x) & (0x7 << 4))
232 #define FMCS_GET(x) (((x) & (0x7 << 4)) >> 4)
233 #define FMCS_SET(x) ((x) << 4)
234 #define AUTOSSR (1 << 3)
235 #define PILTCA (1 << 2)
236 #define SD_PM (1 << 1)
237 #define ST_M (1 << 0)
240 #define AUDIO_CTRL1 (0x09 + BLK2_START)
241 #define TONE_LVL(x) ((x) & (0xf << 4))
242 #define TONE_LVL_GET(x) (((x) & (0xf << 4)) >> 4)
243 #define TONE_LVL_SET(x) ((x) << 4)
244 #define VOL_LVL(x) ((x) & 0xf)
245 #define VOL_LVL_GET(x) ((x) & 0xf)
246 #define VOL_LVL_SET(x) ((x) << 4)
249 #define AUDIO_CTRL2 (0x0a + BLK2_START)
250 #define BASS_PP (1 << 0)
251 #define BASS_P (1 << 1) /* BASS_P, BASS_N are mutually-exclusive */
252 #define BASS_N (1 << 2)
253 #define TREB_P (1 << 3) /* TREB_P, TREB_N are mutually-exclusive */
254 #define TREB_N (1 << 4)
255 #define DEEMP (1 << 5)
256 #define BPFREQ(x) ((x) & (0x3 << 6))
257 #define BPFREQ_2_0K (0x0 << 6)
258 #define BPFREQ_1_0K (0x1 << 6)
259 #define BPFREQ_0_5K (0x2 << 6)
260 #define BPFREQ_HIGH (0x3 << 6)
263 #define PW_SCTRL (0x0b + BLK2_START)
264 #define SS_CTRL(x) ((x) & (0x7 << 5))
265 #define SS_CTRL_GET(x) (((x) & (0x7 << 5)) >> 5)
266 #define SS_CTRL_SET(x) ((x) << 5)
267 #define SM_CTRL(x) ((x) & (0x7 << 2))
268 #define SM_CTRL_GET(x) (((x) & (0x7 << 2)) >> 2)
269 #define SM_CTRL_SET(x) ((x) << 2)
270 #define PW_HPA (1 << 1) /* LV24002 only */
271 #define PW_RAD (1 << 0)
273 /* shadow for writeable registers */
274 #define TUNER_POWERED (1 << 0)
275 #define TUNER_PRESENT (1 << 1)
276 #define TUNER_AWAKE (1 << 2)
277 #define TUNER_PRESENCE_CHECKED (1 << 3)
278 static unsigned tuner_status
= 0;
280 static unsigned char lv24020lp_regs
[0x1c];
282 static const int sw_osc_low
= 10; /* 30; */
283 static const int sw_osc_high
= 240; /* 200; */
284 static const int sw_cap_low
= 0;
285 static const int sw_cap_high
= 191;
287 /* linear coefficients used for tuning */
288 static int coef_00
, coef_01
, coef_10
, coef_11
;
290 /* DAC control register set values */
291 static int if_set
, sd_set
;
293 static inline bool tuner_awake(void)
295 return (tuner_status
& TUNER_AWAKE
) != 0;
298 /* send a byte to the tuner - expects write mode to be current */
299 static void lv24020lp_send_byte(unsigned int byte
)
303 for (i
= 0; i
< 8; i
++)
305 TUNER_GPIO_OUTPUT_VAL_CLEAR(1 << FM_CLOCK_PIN
);
309 TUNER_GPIO_OUTPUT_VAL_SET(1 << FM_DATA_PIN
);
311 TUNER_GPIO_OUTPUT_VAL_CLEAR(1 << FM_DATA_PIN
);
313 udelay(FM_CLK_DELAY
);
315 TUNER_GPIO_OUTPUT_VAL_SET(1 << FM_CLOCK_PIN
);
316 udelay(FM_CLK_DELAY
);
322 /* end a write cycle on the tuner */
323 static void lv24020lp_end_write(void)
325 /* switch back to read mode */
326 TUNER_GPIO_OUTPUT_EN_CLEAR(1 << FM_DATA_PIN
);
327 TUNER_GPIO_OUTPUT_VAL_CLEAR(1 << FM_NRW_PIN
);
328 udelay(FM_CLK_DELAY
);
331 /* prepare a write cycle on the tuner */
332 static unsigned int lv24020lp_begin_write(unsigned int address
)
334 /* Get register's block, translate address */
335 unsigned int blk
= (address
>= BLK2_START
) ?
336 (address
-= BLK2_START
, BLK2
) : BLK1
;
340 /* Prepare 3-wire bus pins for write cycle */
341 TUNER_GPIO_OUTPUT_VAL_SET(1 << FM_NRW_PIN
);
342 TUNER_GPIO_OUTPUT_EN_SET(1 << FM_DATA_PIN
);
343 udelay(FM_CLK_DELAY
);
345 /* current block == register block? */
346 if (blk
== lv24020lp_regs
[BLK_SEL
])
350 lv24020lp_regs
[BLK_SEL
] = blk
;
353 lv24020lp_send_byte(blk
);
355 lv24020lp_send_byte(BLK_SEL
);
357 lv24020lp_end_write();
361 /* write a byte to a tuner register */
362 static void lv24020lp_write(unsigned int address
, unsigned int data
)
364 /* shadow logical values but do logical=>physical remappings on some
366 lv24020lp_regs
[address
] = data
;
376 /* L: 000..063, 064..191
377 * P: 255..192, 127..000 */
378 data
= ((data
< 64) ? 255 : (255 - 64)) - data
;
382 * P: data | always "1" bits */
383 data
|= (1 << 4) | (1 << 1) | (1 << 0);
387 /* Check if interface is turned on */
388 if (!(tuner_status
& TUNER_POWERED
))
391 address
= lv24020lp_begin_write(address
);
394 lv24020lp_send_byte(data
);
396 lv24020lp_send_byte(address
);
398 lv24020lp_end_write();
401 /* helpers to set/clear register bits */
402 static void lv24020lp_write_set(unsigned int address
, unsigned int bits
)
404 lv24020lp_write(address
, lv24020lp_regs
[address
] | bits
);
407 static void lv24020lp_write_clear(unsigned int address
, unsigned int bits
)
409 lv24020lp_write(address
, lv24020lp_regs
[address
] & ~bits
);
412 /* read a byte from a tuner register */
413 static unsigned int lv24020lp_read(unsigned int address
)
418 /* Check if interface is turned on */
419 if (!(tuner_status
& TUNER_POWERED
))
422 address
= lv24020lp_begin_write(address
);
425 lv24020lp_send_byte(address
);
427 lv24020lp_end_write();
431 for (i
= 0; i
< 8; i
++)
433 TUNER_GPIO_OUTPUT_VAL_CLEAR(1 << FM_CLOCK_PIN
);
434 udelay(FM_CLK_DELAY
);
436 if (TUNER_GPIO_INPUT_VAL
& (1 << FM_DATA_PIN
))
439 TUNER_GPIO_OUTPUT_VAL_SET(1 << FM_CLOCK_PIN
);
440 udelay(FM_CLK_DELAY
);
446 /* enables auto frequency centering */
447 static void enable_afc(bool enabled
)
449 unsigned int radio_ctrl1
= lv24020lp_regs
[RADIO_CTRL1
];
453 radio_ctrl1
&= ~RST_AFC
;
454 radio_ctrl1
|= EN_AFC
;
458 radio_ctrl1
|= RST_AFC
;
459 radio_ctrl1
&= ~EN_AFC
;
462 lv24020lp_write(RADIO_CTRL1
, radio_ctrl1
);
465 static int calculate_coef(unsigned fkhz
)
467 /* Overflow below 66000kHz --
468 My tuner tunes down to a min of ~72600kHz but datasheet mentions
469 66000kHz as the minimum. ?? Perhaps 76000kHz was intended? */
470 return fkhz
< 66000 ?
471 0x7fffffff : 0x81d1a47efc5cb700ull
/ ((uint64_t)fkhz
*fkhz
);
474 static int interpolate_x(int expected_y
, int x1
, int x2
, int y1
, int y2
)
477 0 : (int64_t)(expected_y
- y1
)*(x2
- x1
) / (y2
- y1
) + x1
;
480 static int interpolate_y(int expected_x
, int x1
, int x2
, int y1
, int y2
)
483 0 : (int64_t)(expected_x
- x1
)*(y2
- y1
) / (x2
- x1
) + y1
;
486 /* this performs measurements of IF, FM and Stereo frequencies
487 * Input can be: MSS_FM, MSS_IF, MSS_SD */
488 static int tuner_measure(unsigned char type
, int scale
, int duration
)
492 /* enable measuring */
493 lv24020lp_write_set(MSRC_SEL
, type
);
494 lv24020lp_write_clear(CNT_CTRL
, CNT_SEL
);
495 lv24020lp_write_set(RADIO_CTRL1
, EN_MEAS
);
498 lv24020lp_write_set(CNT_CTRL
, CNT1_CLR
);
499 lv24020lp_write_clear(CNT_CTRL
, CNT1_CLR
);
501 /* start counter, delay for specified time and stop it */
502 lv24020lp_write_set(CNT_CTRL
, CNT_EN
);
505 /* obtain actual duration, including interrupts that occurred and
506 * the time to write the counter stop */
507 long usec
= USEC_TIMER
;
510 udelay(duration
*1000);
512 lv24020lp_write_clear(CNT_CTRL
, CNT_EN
);
515 duration
= (USEC_TIMER
- usec
) / 1000;
518 /* This function takes a loooong time and other stuff needs
522 /* read tick count */
523 finval
= (lv24020lp_read(CNT_H
) << 8) | lv24020lp_read(CNT_L
);
525 /* restore measure mode */
526 lv24020lp_write_clear(RADIO_CTRL1
, EN_MEAS
);
527 lv24020lp_write_clear(MSRC_SEL
, type
);
531 finval
= scale
*finval
*256 / duration
;
533 finval
= scale
*finval
/ duration
;
538 /* set the FM oscillator frequency */
539 static void set_frequency(int freq
)
541 int coef
, cap_value
, osc_value
;
547 TUNER_LOG("set_frequency(%d)\n", freq
);
551 /* For the LV2400x, the tuned frequency is the sum of the displayed
552 * frequency and the preset IF frequency, in formula:
553 * Tuned FM frequency = displayed frequency + preset IF frequency
555 * For example: when the IF frequency of LV2400x is preset at 110 kHz,
556 * it must be tuned at 88.51 MHz to receive the radio station at 88.4 MHz.
557 * -- AN2400S04@ – V0.4
564 TUNER_LOG("Select cap:\n");
566 coef
= calculate_coef(freq
);
567 cap_value
= interpolate_x(coef
, sw_cap_low
, sw_cap_high
,
570 osc_value
= sw_osc_low
;
571 lv24020lp_write(FM_OSC
, osc_value
);
573 /* Just in case - don't go into infinite loop */
574 for (count
= 0; count
< 30; count
++)
576 int y0
= interpolate_y(cap_value
, sw_cap_low
, sw_cap_high
,
578 int y1
= interpolate_y(cap_value
, sw_cap_low
, sw_cap_high
,
580 int coef_fcur
, cap_new
, coef_cor
, range
;
582 lv24020lp_write(FM_CAP
, cap_value
);
585 f1
= tuner_measure(MSS_FM
, 1, 16);
586 coef_fcur
= calculate_coef(f1
);
587 coef_cor
= calculate_coef((f1
*1000 + 32*256) / 1000);
591 TUNER_LOG("%d %d %d %d %d %d %d %d\n",
592 f1
, cap_value
, coef
, coef_fcur
, coef_cor
, y0
, y1
, range
);
594 if (coef
>= y0
&& coef
<= y1
)
596 osc_value
= interpolate_x(coef
, sw_osc_low
, sw_osc_high
,
599 if (osc_value
>= sw_osc_low
&& osc_value
<= sw_osc_high
)
603 cap_new
= interpolate_x(coef
, cap_value
, sw_cap_high
,
606 if (cap_new
== cap_value
)
608 if (coef
< coef_fcur
)
619 TUNER_LOG("osc_value: %d\n", osc_value
);
621 TUNER_LOG("Tune:\n");
623 x1
= sw_osc_low
, x2
= sw_osc_high
;
624 /* FM_OSC already at SW_OSC low and f1 is already the measured
631 lv24020lp_write(FM_OSC
, x2
);
632 f2
= tuner_measure(MSS_FM
, 1, 16);
634 if (abs(f2
- freq
) <= 16)
636 TUNER_LOG("%d %d %d %d\n", f1
, f2
, x1
, x2
);
640 x2_new
= interpolate_x(freq
, x1
, x2
, f1
, f2
);
642 x1
= x2
, f1
= f2
, x2
= x2_new
;
643 TUNER_LOG("%d %d %d %d\n", f1
, f2
, x1
, x2
);
649 /* May still be close enough */
650 TUNER_LOG("tuning failed - diff: %d\n", f2
- freq
);
660 #define TOO_SMALL (1 << 0)
661 #define TOO_BIG (1 << 1)
662 #define APPROACH_UP_1 (1 << 2)
663 #define APPROACH_DOWN_1 (1 << 3)
665 static void fine_step_tune(int (*setcmp
)(int regval
), int regval
, int step
)
667 /* Registers are not always stable, timeout if best fit not found soon
669 unsigned long abort
= current_tick
+ HZ
*2;
672 while (TIME_BEFORE(current_tick
, abort
))
676 regval
= regval
+ step
;
678 cmp
= setcmp(regval
);
689 flags
|= APPROACH_UP_1
;
696 step
|= APPROACH_DOWN_1
;
699 if ((flags
& APPROACH_UP_1
) && (flags
& APPROACH_DOWN_1
))
700 break; /* approached with step=1: best fit value found */
702 if ((flags
& TOO_SMALL
) && (flags
& TOO_BIG
))
707 flags
&= ~(TOO_SMALL
| TOO_BIG
);
712 static int if_setcmp(int regval
)
714 lv24020lp_write(IF_OSC
, regval
);
715 lv24020lp_write(IF_CENTER
, regval
);
716 lv24020lp_write(IF_BW
, 65*regval
/100);
718 if_set
= tuner_measure(MSS_IF
, 1000, 32);
720 /* This register is bounces around by a few hundred Hz and doesn't seem
721 to be precisely tuneable. Just do 110000 +/- 500 since it's not very
722 critical it seems. */
723 if (abs(if_set
- 110000) <= 500)
726 return if_set
< 110000 ? -1 : 1;
729 static int sd_setcmp(int regval
)
731 lv24020lp_write(SD_OSC
, regval
);
733 sd_set
= tuner_measure(MSS_SD
, 1000, 32);
735 if (abs(sd_set
- 38300) <= 31)
738 return sd_set
< 38300 ? -1 : 1;
741 static void set_sleep(bool sleep
)
744 if (sleep
|| tuner_awake())
747 if ((tuner_status
& (TUNER_PRESENT
| TUNER_POWERED
)) !=
748 (TUNER_PRESENT
| TUNER_POWERED
))
753 /* 2. Calibrate the IF frequency at 110 kHz: */
754 lv24020lp_write_clear(RADIO_CTRL2
, IF_PM_L
);
755 fine_step_tune(if_setcmp
, 0x80, 8);
756 lv24020lp_write_set(RADIO_CTRL2
, IF_PM_L
);
758 /* 3. Calibrate the stereo decoder clock at 38.3 kHz: */
759 lv24020lp_write_set(STEREO_CTRL
, SD_PM
);
760 fine_step_tune(sd_setcmp
, 0x80, 8);
761 lv24020lp_write_clear(STEREO_CTRL
, SD_PM
);
763 /* calculate FM tuning coefficients */
764 lv24020lp_write(FM_CAP
, sw_cap_low
);
765 lv24020lp_write(FM_OSC
, sw_osc_low
);
766 coef_00
= calculate_coef(tuner_measure(MSS_FM
, 1, 64));
768 lv24020lp_write(FM_CAP
, sw_cap_high
);
769 coef_01
= calculate_coef(tuner_measure(MSS_FM
, 1, 64));
771 lv24020lp_write(FM_CAP
, sw_cap_low
);
772 lv24020lp_write(FM_OSC
, sw_osc_high
);
773 coef_10
= calculate_coef(tuner_measure(MSS_FM
, 1, 64));
775 lv24020lp_write(FM_CAP
, sw_cap_high
);
776 coef_11
= calculate_coef(tuner_measure(MSS_FM
, 1, 64));
778 /* set various audio level settings */
779 lv24020lp_write(AUDIO_CTRL1
, TONE_LVL_SET(0) | VOL_LVL_SET(0));
780 lv24020lp_write_set(RADIO_CTRL2
, AGCSP
);
781 lv24020lp_write_set(RADIO_CTRL3
, VOLSH
);
782 lv24020lp_write(STEREO_CTRL
, FMCS_SET(7) | AUTOSSR
);
783 lv24020lp_write(PW_SCTRL
, SS_CTRL_SET(3) | SM_CTRL_SET(1) |
786 tuner_status
|= TUNER_AWAKE
;
789 static int lp24020lp_tuned(void)
791 return RSS_FS(lv24020lp_read(RADIO_STAT
)) < 0x1f;
794 static int lv24020lp_debug_info(int setting
)
798 if (setting
>= LV24020LP_DEBUG_FIRST
&& setting
<= LV24020LP_DEBUG_LAST
)
806 /* tuner-specific debug info */
807 case LV24020LP_CTRL_STAT
:
808 val
= lv24020lp_read(CTRL_STAT
);
811 case LV24020LP_REG_STAT
:
812 val
= lv24020lp_read(RADIO_STAT
);
815 case LV24020LP_MSS_FM
:
816 val
= tuner_measure(MSS_FM
, 1, 16);
819 case LV24020LP_MSS_IF
:
820 val
= tuner_measure(MSS_IF
, 1000, 16);
823 case LV24020LP_MSS_SD
:
824 val
= tuner_measure(MSS_SD
, 1000, 16);
827 case LV24020LP_IF_SET
:
831 case LV24020LP_SD_SET
:
841 /** Public interfaces **/
842 void lv24020lp_init(void)
844 mutex_init(&tuner_mtx
);
847 void lv24020lp_lock(void)
849 mutex_lock(&tuner_mtx
);
852 void lv24020lp_unlock(void)
854 mutex_unlock(&tuner_mtx
);
857 /* This function expects the driver to be locked externally */
858 void lv24020lp_power(bool status
)
860 static const unsigned char tuner_defaults
[][2] =
862 /* Block 1 writeable registers */
863 { MSRC_SEL
, AFC_LVL
},
867 { CNT_CTRL
, CNT1_CLR
| SWP_CNT_L
},
868 { IRQ_MSK
, 0x00 }, /* IRQ_LVL -> Low to High */
870 /* { IRQ_OUT, 0x00 }, No action on this register (skip) */
871 /* Block 2 writeable registers */
872 { RADIO_CTRL1
, EN_AFC
},
874 { IF_BW
, 65*0x80 / 100 }, /* 65% of IF_OSC */
875 { RADIO_CTRL2
, IF_PM_L
},
876 { RADIO_CTRL3
, AGC_SLVL
| SE_FM
},
877 { STEREO_CTRL
, FMCS_SET(4) | AUTOSSR
},
878 { AUDIO_CTRL1
, TONE_LVL_SET(7) | VOL_LVL_SET(7) },
879 { AUDIO_CTRL2
, BPFREQ_HIGH
}, /* deemphasis 50us */
880 { PW_SCTRL
, SS_CTRL_SET(3) | SM_CTRL_SET(3) | PW_RAD
},
887 tuner_status
|= (TUNER_PRESENCE_CHECKED
| TUNER_POWERED
);
889 /* if tuner is present, CHIP ID is 0x09 */
890 if (lv24020lp_read(CHIP_ID
) == 0x09)
892 tuner_status
|= TUNER_PRESENT
;
894 /* After power-up, the LV2400x needs to be initialized as
897 /* 1. Write default values to the registers: */
898 lv24020lp_regs
[BLK_SEL
] = 0; /* Force a switch on the first */
899 for (i
= 0; i
< ARRAYLEN(tuner_defaults
); i
++)
900 lv24020lp_write(tuner_defaults
[i
][0], tuner_defaults
[i
][1]);
902 /* Complete the startup calibration if the tuner is woken */
909 if (tuner_status
& TUNER_PRESENT
)
910 lv24020lp_write_clear(PW_SCTRL
, PW_RAD
);
912 tuner_status
&= ~(TUNER_POWERED
| TUNER_AWAKE
);
916 int lv24020lp_set(int setting
, int value
)
920 mutex_lock(&tuner_mtx
);
928 case RADIO_FREQUENCY
:
929 set_frequency(value
);
932 case RADIO_SCAN_FREQUENCY
:
933 /* TODO: really implement this */
934 set_frequency(value
);
935 val
= lp24020lp_tuned();
940 lv24020lp_write_clear(RADIO_CTRL3
, AMUTE_L
);
942 lv24020lp_write_set(RADIO_CTRL3
, AMUTE_L
);
947 const struct fm_region_data
*rd
= &fm_region_data
[value
];
948 if (rd
->deemphasis
== 75)
949 lv24020lp_write_set(AUDIO_CTRL2
, DEEMP
);
951 lv24020lp_write_clear(AUDIO_CTRL2
, DEEMP
);
955 case RADIO_FORCE_MONO
:
957 lv24020lp_write_set(STEREO_CTRL
, ST_M
);
959 lv24020lp_write_clear(STEREO_CTRL
, ST_M
);
966 mutex_unlock(&tuner_mtx
);
971 int lv24020lp_get(int setting
)
974 const unsigned char fst
[7] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f};
975 unsigned char fst_ndx
, fs
;
977 mutex_lock(&tuner_mtx
);
982 /* TODO: really implement this */
983 val
= lp24020lp_tuned();
987 val
= (lv24020lp_read(RADIO_STAT
) & RSS_MS
) != 0;
992 bool fmstatus
= true;
994 if (!(tuner_status
& TUNER_PRESENCE_CHECKED
))
995 fmstatus
= tuner_power(true);
997 val
= (tuner_status
& TUNER_PRESENT
) != 0;
1005 fs
= RSS_FS(lv24020lp_read(RADIO_STAT
));
1006 for(fst_ndx
=0; fst_ndx
<7; fst_ndx
++)
1007 if(fs
== fst
[fst_ndx
])
1009 val
= 75 - 10*fst_ndx
;
1012 case RADIO_RSSI_MIN
:
1016 case RADIO_RSSI_MAX
:
1021 val
= lv24020lp_debug_info(setting
);
1024 mutex_unlock(&tuner_mtx
);
1028 #endif /* BOOTLOADER */