Use bus reset detection for all ARC OTG devices. Remove conflict from LV24020LP drive...
[kugel-rb.git] / firmware / drivers / tuner / lv24020lp.c
blob9d6425b9626244db278b250dd7282f3940bf62c7
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
23 #include <stdbool.h>
24 #include <stdlib.h>
25 #include "config.h"
26 #include "thread.h"
27 #include "kernel.h"
28 #include "tuner.h" /* tuner abstraction interface */
29 #include "power.h"
30 #include "fmradio.h" /* physical interface driver */
31 #include "sound.h"
32 #include "pp5024.h"
33 #include "system.h"
35 #ifndef BOOTLOADER
37 static struct mutex tuner_mtx;
39 #if 0
40 /* define to enable tuner logging */
41 #define SANYO_TUNER_LOG
42 #endif
44 #ifdef SANYO_TUNER_LOG
45 #include "sprintf.h"
46 #include "file.h"
48 static int fd_log = -1;
50 #define TUNER_LOG_OPEN() if (fd_log < 0) \
51 fd_log = creat("/tuner_dump.txt")
52 /* syncing required because close() is never called */
53 #define TUNER_LOG_SYNC() fsync(fd_log)
54 #define TUNER_LOG(s...) fdprintf(fd_log, s)
55 #else
56 #define TUNER_LOG_OPEN()
57 #define TUNER_LOG_SYNC()
58 #define TUNER_LOG(s...)
59 #endif /* SANYO_TUNER_LOG */
61 /** tuner register defines **/
63 #if defined(SANSA_E200) || defined(SANSA_C200)
64 #define TUNER_GPIO_OUTPUT_EN GPIOH_OUTPUT_EN
65 #define TUNER_GPIO_OUTPUT_VAL GPIOH_OUTPUT_VAL
66 #define TUNER_GPIO_INPUT_VAL GPIOH_INPUT_VAL
67 #define FM_NRW_PIN 3
68 #define FM_CLOCK_PIN 4
69 #define FM_DATA_PIN 5
71 #elif defined(IAUDIO_7)
72 #define TUNER_GPIO_OUTPUT_EN GPIOA_DIR
73 #define TUNER_GPIO_OUTPUT_VAL GPIOA
74 #define TUNER_GPIO_INPUT_VAL GPIOA
75 #define FM_CLOCK_PIN 5
76 #define FM_DATA_PIN 6
77 #define FM_NRW_PIN 7
78 //#define udelay(x) /* Remove hack when D2 has udelay */
80 static void udelay(int usecs)
82 while (usecs--)
83 asm("nop;nop;");
86 #elif defined(COWON_D2)
87 #define TUNER_GPIO_OUTPUT_EN GPIOC_DIR
88 #define TUNER_GPIO_OUTPUT_VAL GPIOC
89 #define TUNER_GPIO_INPUT_VAL GPIOC
90 #define FM_NRW_PIN 31
91 #define FM_CLOCK_PIN 29
92 #define FM_DATA_PIN 30
93 #define udelay(x) /* Remove hack when D2 has udelay */
94 #else
95 #error GPIOs undefined for this target
96 #endif
98 #define FM_CLK_DELAY 1
100 /* block 1 registers */
102 /* R */
103 #define CHIP_ID 0x00
105 /* W */
106 #define BLK_SEL 0x01
107 #define BLK1 0x01
108 #define BLK2 0x02
110 /* W */
111 #define MSRC_SEL 0x02
112 #define MSR_O (1 << 7)
113 #define AFC_LVL (1 << 6)
114 #define AFC_SPD (1 << 5)
115 #define MSS_SD (1 << 2)
116 #define MSS_FM (1 << 1)
117 #define MSS_IF (1 << 0)
119 /* W */
120 #define FM_OSC 0x03
122 /* W */
123 #define SD_OSC 0x04
125 /* W */
126 #define IF_OSC 0x05
128 /* W */
129 #define CNT_CTRL 0x06
130 #define CNT1_CLR (1 << 7)
131 #define CTAB(x) ((x) & (0x7 << 4))
132 #define CTAB_STOP_2 (0x0 << 4)
133 #define CTAB_STOP_8 (0x1 << 4)
134 #define CTAB_STOP_32 (0x2 << 4)
135 #define CTAB_STOP_128 (0x3 << 4)
136 #define CTAB_STOP_512 (0x4 << 4)
137 #define CTAB_STOP_2048 (0x5 << 4)
138 #define CTAB_STOP_8192 (0x6 << 4)
139 #define CTAB_STOP_32768 (0x7 << 4)
140 #define SWP_CNT_L (1 << 3)
141 #define CNT_EN (1 << 2)
142 #define CNT_SEL (1 << 1)
143 #define CNT_SET (1 << 0)
145 /* W */
146 #define IRQ_MSK 0x08
147 #define IM_MS (1 << 6)
148 #define IRQ_LVL (1 << 3)
149 #define IM_AFC (1 << 2)
150 #define IM_FS (1 << 1)
151 #define IM_CNT2 (1 << 0)
153 /* W */
154 #define FM_CAP 0x09
156 /* R */
157 #define CNT_L 0x0a /* Counter register low value */
159 /* R */
160 #define CNT_H 0x0b /* Counter register high value */
162 /* R */
163 #define CTRL_STAT 0x0c
164 #define AFC_FLG (1 << 0)
166 /* R */
167 #define RADIO_STAT 0x0d
168 #define RSS_MS (1 << 7)
169 #define RSS_FS(x) ((x) & 0x7f)
170 #define RSS_FS_GET(x) ((x) & 0x7f)
171 #define RSS_FS_SET(x) (x)
172 /* Note: Reading this register will clear field strength and mono/stereo interrupt. */
174 /* R */
175 #define IRQ_ID 0x0e
176 #define II_CNT2 (1 << 5)
177 #define II_AFC (1 << 3)
178 #define II_FS_MS (1 << 0)
180 /* W */
181 #define IRQ_OUT 0x0f
183 /* block 2 registers - offset added in order to id and avoid manual
184 switching */
185 #define BLK2_START 0x10
187 /* W */
188 #define RADIO_CTRL1 (0x02 + BLK2_START)
189 #define EN_MEAS (1 << 7)
190 #define EN_AFC (1 << 6)
191 #define DIR_AFC (1 << 3)
192 #define RST_AFC (1 << 2)
194 /* W */
195 #define IF_CENTER (0x03 + BLK2_START)
197 /* W */
198 #define IF_BW (0x05 + BLK2_START)
200 /* W */
201 #define RADIO_CTRL2 (0x06 + BLK2_START)
202 #define VREF2 (1 << 7)
203 #define VREF (1 << 6)
204 #define STABI_BP (1 << 5)
205 #define IF_PM_L (1 << 4)
206 #define AGCSP (1 << 1)
207 #define AM_ANT_BSW (1 << 0) /* ?? */
209 /* W */
210 #define RADIO_CTRL3 (0x07 + BLK2_START)
211 #define AGC_SLVL (1 << 7)
212 #define VOLSH (1 << 6)
213 #define TB_ON (1 << 5)
214 #define AMUTE_L (1 << 4)
215 #define SE_FM (1 << 3)
216 #define SE_BE (1 << 1)
217 #define SE_EXT (1 << 0) /* For LV24000=0, LV24001/24002=Ext source enab. */
219 /* W */
220 #define STEREO_CTRL (0x08 + BLK2_START)
221 #define FRCST (1 << 7)
222 #define FMCS(x) ((x) & (0x7 << 4))
223 #define FMCS_GET(x) (((x) & (0x7 << 4)) >> 4)
224 #define FMCS_SET(x) ((x) << 4)
225 #define AUTOSSR (1 << 3)
226 #define PILTCA (1 << 2)
227 #define SD_PM (1 << 1)
228 #define ST_M (1 << 0)
230 /* W */
231 #define AUDIO_CTRL1 (0x09 + BLK2_START)
232 #define TONE_LVL(x) ((x) & (0xf << 4))
233 #define TONE_LVL_GET(x) (((x) & (0xf << 4)) >> 4)
234 #define TONE_LVL_SET(x) ((x) << 4)
235 #define VOL_LVL(x) ((x) & 0xf)
236 #define VOL_LVL_GET(x) ((x) & 0xf)
237 #define VOL_LVL_SET(x) ((x) << 4)
239 /* W */
240 #define AUDIO_CTRL2 (0x0a + BLK2_START)
241 #define BASS_PP (1 << 0)
242 #define BASS_P (1 << 1) /* BASS_P, BASS_N are mutually-exclusive */
243 #define BASS_N (1 << 2)
244 #define TREB_P (1 << 3) /* TREB_P, TREB_N are mutually-exclusive */
245 #define TREB_N (1 << 4)
246 #define DEEMP (1 << 5)
247 #define BPFREQ(x) ((x) & (0x3 << 6))
248 #define BPFREQ_2_0K (0x0 << 6)
249 #define BPFREQ_1_0K (0x1 << 6)
250 #define BPFREQ_0_5K (0x2 << 6)
251 #define BPFREQ_HIGH (0x3 << 6)
253 /* W */
254 #define PW_SCTRL (0x0b + BLK2_START)
255 #define SS_CTRL(x) ((x) & (0x7 << 5))
256 #define SS_CTRL_GET(x) (((x) & (0x7 << 5)) >> 5)
257 #define SS_CTRL_SET(x) ((x) << 5)
258 #define SM_CTRL(x) ((x) & (0x7 << 2))
259 #define SM_CTRL_GET(x) (((x) & (0x7 << 2)) >> 2)
260 #define SM_CTRL_SET(x) ((x) << 2)
261 #define PW_HPA (1 << 1) /* LV24002 only */
262 #define PW_RAD (1 << 0)
264 /* shadow for writeable registers */
265 #define TUNER_POWERED (1 << 0)
266 #define TUNER_PRESENT (1 << 1)
267 #define TUNER_AWAKE (1 << 2)
268 #define TUNER_PRESENCE_CHECKED (1 << 3)
269 static unsigned tuner_status = 0;
271 static unsigned char lv24020lp_regs[0x1c];
273 static const int sw_osc_low = 10; /* 30; */
274 static const int sw_osc_high = 240; /* 200; */
275 static const int sw_cap_low = 0;
276 static const int sw_cap_high = 191;
278 /* linear coefficients used for tuning */
279 static int coef_00, coef_01, coef_10, coef_11;
281 /* DAC control register set values */
282 static int if_set, sd_set;
284 static inline bool tuner_awake(void)
286 return (tuner_status & TUNER_AWAKE) != 0;
289 /* send a byte to the tuner - expects write mode to be current */
290 static void lv24020lp_send_byte(unsigned int byte)
292 int i;
294 for (i = 0; i < 8; i++)
296 TUNER_GPIO_OUTPUT_VAL &= ~(1 << FM_CLOCK_PIN);
298 if (byte & 1)
299 TUNER_GPIO_OUTPUT_VAL |= (1 << FM_DATA_PIN);
300 else
301 TUNER_GPIO_OUTPUT_VAL &= ~(1 << FM_DATA_PIN);
303 udelay(FM_CLK_DELAY);
305 TUNER_GPIO_OUTPUT_VAL |= (1 << FM_CLOCK_PIN);
306 udelay(FM_CLK_DELAY);
308 byte >>= 1;
312 /* end a write cycle on the tuner */
313 static void lv24020lp_end_write(void)
315 /* switch back to read mode */
316 TUNER_GPIO_OUTPUT_EN &= ~(1 << FM_DATA_PIN);
317 TUNER_GPIO_OUTPUT_VAL &= ~(1 << FM_NRW_PIN);
318 udelay(FM_CLK_DELAY);
321 /* prepare a write cycle on the tuner */
322 static unsigned int lv24020lp_begin_write(unsigned int address)
324 /* Get register's block, translate address */
325 unsigned int blk = (address >= BLK2_START) ?
326 (address -= BLK2_START, BLK2) : BLK1;
328 for (;;)
330 /* Prepare 3-wire bus pins for write cycle */
331 TUNER_GPIO_OUTPUT_VAL |= (1 << FM_NRW_PIN);
332 TUNER_GPIO_OUTPUT_EN |= (1 << FM_DATA_PIN);
333 udelay(FM_CLK_DELAY);
335 /* current block == register block? */
336 if (blk == lv24020lp_regs[BLK_SEL])
337 return address;
339 /* switch block */
340 lv24020lp_regs[BLK_SEL] = blk;
342 /* data first */
343 lv24020lp_send_byte(blk);
344 /* then address */
345 lv24020lp_send_byte(BLK_SEL);
347 lv24020lp_end_write();
351 /* write a byte to a tuner register */
352 static void lv24020lp_write(unsigned int address, unsigned int data)
354 /* shadow logical values but do logical=>physical remappings on some
355 registers' data. */
356 lv24020lp_regs[address] = data;
358 switch (address)
360 case FM_OSC:
361 /* L: 000..255
362 * P: 255..000 */
363 data = 255 - data;
364 break;
365 case FM_CAP:
366 /* L: 000..063, 064..191
367 * P: 255..192, 127..000 */
368 data = ((data < 64) ? 255 : (255 - 64)) - data;
369 break;
370 case RADIO_CTRL1:
371 /* L: data
372 * P: data | always "1" bits */
373 data |= (1 << 4) | (1 << 1) | (1 << 0);
374 break;
377 /* Check if interface is turned on */
378 if (!(tuner_status & TUNER_POWERED))
379 return;
381 address = lv24020lp_begin_write(address);
383 /* data first */
384 lv24020lp_send_byte(data);
385 /* then address */
386 lv24020lp_send_byte(address);
388 lv24020lp_end_write();
391 /* helpers to set/clear register bits */
392 static void lv24020lp_write_set(unsigned int address, unsigned int bits)
394 lv24020lp_write(address, lv24020lp_regs[address] | bits);
397 static void lv24020lp_write_clear(unsigned int address, unsigned int bits)
399 lv24020lp_write(address, lv24020lp_regs[address] & ~bits);
402 /* read a byte from a tuner register */
403 static unsigned int lv24020lp_read(unsigned int address)
405 int i;
406 unsigned int toread;
408 /* Check if interface is turned on */
409 if (!(tuner_status & TUNER_POWERED))
410 return 0;
412 address = lv24020lp_begin_write(address);
414 /* address */
415 lv24020lp_send_byte(address);
417 lv24020lp_end_write();
419 /* data */
420 toread = 0;
421 for (i = 0; i < 8; i++)
423 TUNER_GPIO_OUTPUT_VAL &= ~(1 << FM_CLOCK_PIN);
424 udelay(FM_CLK_DELAY);
426 if (TUNER_GPIO_INPUT_VAL & (1 << FM_DATA_PIN))
427 toread |= (1 << i);
429 TUNER_GPIO_OUTPUT_VAL |= (1 << FM_CLOCK_PIN);
430 udelay(FM_CLK_DELAY);
433 return toread;
436 /* enables auto frequency centering */
437 static void enable_afc(bool enabled)
439 unsigned int radio_ctrl1 = lv24020lp_regs[RADIO_CTRL1];
441 if (enabled)
443 radio_ctrl1 &= ~RST_AFC;
444 radio_ctrl1 |= EN_AFC;
446 else
448 radio_ctrl1 |= RST_AFC;
449 radio_ctrl1 &= ~EN_AFC;
452 lv24020lp_write(RADIO_CTRL1, radio_ctrl1);
455 static int calculate_coef(unsigned fkhz)
457 /* Overflow below 66000kHz --
458 My tuner tunes down to a min of ~72600kHz but datasheet mentions
459 66000kHz as the minimum. ?? Perhaps 76000kHz was intended? */
460 return fkhz < 66000 ?
461 0x7fffffff : 0x81d1a47efc5cb700ull / ((uint64_t)fkhz*fkhz);
464 static int interpolate_x(int expected_y, int x1, int x2, int y1, int y2)
466 return y1 == y2 ?
467 0 : (int64_t)(expected_y - y1)*(x2 - x1) / (y2 - y1) + x1;
470 static int interpolate_y(int expected_x, int x1, int x2, int y1, int y2)
472 return x1 == x2 ?
473 0 : (int64_t)(expected_x - x1)*(y2 - y1) / (x2 - x1) + y1;
476 /* this performs measurements of IF, FM and Stereo frequencies
477 * Input can be: MSS_FM, MSS_IF, MSS_SD */
478 static int tuner_measure(unsigned char type, int scale, int duration)
480 int64_t finval;
482 /* enable measuring */
483 lv24020lp_write_set(MSRC_SEL, type);
484 lv24020lp_write_clear(CNT_CTRL, CNT_SEL);
485 lv24020lp_write_set(RADIO_CTRL1, EN_MEAS);
487 /* reset counter */
488 lv24020lp_write_set(CNT_CTRL, CNT1_CLR);
489 lv24020lp_write_clear(CNT_CTRL, CNT1_CLR);
491 /* start counter, delay for specified time and stop it */
492 lv24020lp_write_set(CNT_CTRL, CNT_EN);
493 udelay(duration*1000 - 16);
494 lv24020lp_write_clear(CNT_CTRL, CNT_EN);
496 /* read tick count */
497 finval = (lv24020lp_read(CNT_H) << 8) | lv24020lp_read(CNT_L);
499 /* restore measure mode */
500 lv24020lp_write_clear(RADIO_CTRL1, EN_MEAS);
501 lv24020lp_write_clear(MSRC_SEL, type);
503 /* convert value */
504 if (type == MSS_FM)
505 finval = scale*finval*256 / duration;
506 else
507 finval = scale*finval / duration;
509 /* This function takes a loooong time and other stuff needs
510 running by now */
511 yield();
513 return (int)finval;
516 /* set the FM oscillator frequency */
517 static void set_frequency(int freq)
519 int coef, cap_value, osc_value;
520 int f1, f2, x1, x2;
521 int count;
523 TUNER_LOG_OPEN();
525 TUNER_LOG("set_frequency(%d)\n", freq);
527 enable_afc(false);
529 /* MHz -> kHz */
530 freq /= 1000;
532 TUNER_LOG("Select cap:\n");
534 coef = calculate_coef(freq);
535 cap_value = interpolate_x(coef, sw_cap_low, sw_cap_high,
536 coef_00, coef_01);
538 osc_value = sw_osc_low;
539 lv24020lp_write(FM_OSC, osc_value);
541 /* Just in case - don't go into infinite loop */
542 for (count = 0; count < 30; count++)
544 int y0 = interpolate_y(cap_value, sw_cap_low, sw_cap_high,
545 coef_00, coef_01);
546 int y1 = interpolate_y(cap_value, sw_cap_low, sw_cap_high,
547 coef_10, coef_11);
548 int coef_fcur, cap_new, coef_cor, range;
550 lv24020lp_write(FM_CAP, cap_value);
552 range = y1 - y0;
553 f1 = tuner_measure(MSS_FM, 1, 16);
554 coef_fcur = calculate_coef(f1);
555 coef_cor = calculate_coef((f1*1000 + 32*256) / 1000);
556 y0 = coef_cor;
557 y1 = y0 + range;
559 TUNER_LOG("%d %d %d %d %d %d %d %d\n",
560 f1, cap_value, coef, coef_fcur, coef_cor, y0, y1, range);
562 if (coef >= y0 && coef <= y1)
564 osc_value = interpolate_x(coef, sw_osc_low, sw_osc_high,
565 y0, y1);
567 if (osc_value >= sw_osc_low && osc_value <= sw_osc_high)
568 break;
571 cap_new = interpolate_x(coef, cap_value, sw_cap_high,
572 coef_fcur, coef_01);
574 if (cap_new == cap_value)
576 if (coef < coef_fcur)
577 cap_value++;
578 else
579 cap_value--;
581 else
583 cap_value = cap_new;
587 TUNER_LOG("osc_value: %d\n", osc_value);
589 TUNER_LOG("Tune:\n");
591 x1 = sw_osc_low, x2 = sw_osc_high;
592 /* FM_OSC already at SW_OSC low and f1 is already the measured
593 frequency */
597 int x2_new;
599 lv24020lp_write(FM_OSC, x2);
600 f2 = tuner_measure(MSS_FM, 1, 16);
602 if (abs(f2 - freq) <= 16)
604 TUNER_LOG("%d %d %d %d\n", f1, f2, x1, x2);
605 break;
608 x2_new = interpolate_x(freq, x1, x2, f1, f2);
610 x1 = x2, f1 = f2, x2 = x2_new;
611 TUNER_LOG("%d %d %d %d\n", f1, f2, x1, x2);
613 while (x2 != 0);
615 if (x2 == 0)
617 /* May still be close enough */
618 TUNER_LOG("tuning failed - diff: %d\n", f2 - freq);
621 enable_afc(true);
623 TUNER_LOG("\n");
625 TUNER_LOG_SYNC();
628 #define TOO_SMALL (1 << 0)
629 #define TOO_BIG (1 << 1)
630 #define APPROACH_UP_1 (1 << 2)
631 #define APPROACH_DOWN_1 (1 << 3)
633 static void fine_step_tune(int (*setcmp)(int regval), int regval, int step)
635 /* Registers are not always stable, timeout if best fit not found soon
636 enough */
637 unsigned long abort = current_tick + HZ*2;
638 int flags = 0;
640 while (TIME_BEFORE(current_tick, abort))
642 int cmp;
644 regval = regval + step;
646 cmp = setcmp(regval);
648 if (cmp == 0)
649 break;
651 step = abs(step);
653 if (cmp < 0)
655 flags |= TOO_SMALL;
656 if (step == 1)
657 flags |= APPROACH_UP_1;
659 else
661 step = -step;
662 flags |= TOO_BIG;
663 if (step == -1)
664 step |= APPROACH_DOWN_1;
667 if ((flags & APPROACH_UP_1) && (flags & APPROACH_DOWN_1))
668 break; /* approached with step=1: best fit value found */
670 if ((flags & TOO_SMALL) && (flags & TOO_BIG))
672 step /= 2;
673 if (step == 0)
674 step = 1;
675 flags &= ~(TOO_SMALL | TOO_BIG);
680 static int if_setcmp(int regval)
682 lv24020lp_write(IF_OSC, regval);
683 lv24020lp_write(IF_CENTER, regval);
684 lv24020lp_write(IF_BW, 65*regval/100);
686 if_set = tuner_measure(MSS_IF, 1000, 32);
688 /* This register is bounces around by a few hundred Hz and doesn't seem
689 to be precisely tuneable. Just do 110000 +/- 500 since it's not very
690 critical it seems. */
691 if (abs(if_set - 110000) <= 500)
692 return 0;
694 return if_set < 110000 ? -1 : 1;
697 static int sd_setcmp(int regval)
699 lv24020lp_write(SD_OSC, regval);
701 sd_set = tuner_measure(MSS_SD, 1000, 32);
703 if (abs(sd_set - 38300) <= 31)
704 return 0;
706 return sd_set < 38300 ? -1 : 1;
709 static void set_sleep(bool sleep)
711 if (sleep || tuner_awake())
712 return;
714 if ((tuner_status & (TUNER_PRESENT | TUNER_POWERED)) !=
715 (TUNER_PRESENT | TUNER_POWERED))
716 return;
718 enable_afc(false);
720 /* 2. Calibrate the IF frequency at 110 kHz: */
721 lv24020lp_write_clear(RADIO_CTRL2, IF_PM_L);
722 fine_step_tune(if_setcmp, 0x80, 8);
723 lv24020lp_write_set(RADIO_CTRL2, IF_PM_L);
725 /* 3. Calibrate the stereo decoder clock at 38.3 kHz: */
726 lv24020lp_write_set(STEREO_CTRL, SD_PM);
727 fine_step_tune(sd_setcmp, 0x80, 8);
728 lv24020lp_write_clear(STEREO_CTRL, SD_PM);
730 /* calculate FM tuning coefficients */
731 lv24020lp_write(FM_CAP, sw_cap_low);
732 lv24020lp_write(FM_OSC, sw_osc_low);
733 coef_00 = calculate_coef(tuner_measure(MSS_FM, 1, 64));
735 lv24020lp_write(FM_CAP, sw_cap_high);
736 coef_01 = calculate_coef(tuner_measure(MSS_FM, 1, 64));
738 lv24020lp_write(FM_CAP, sw_cap_low);
739 lv24020lp_write(FM_OSC, sw_osc_high);
740 coef_10 = calculate_coef(tuner_measure(MSS_FM, 1, 64));
742 lv24020lp_write(FM_CAP, sw_cap_high);
743 coef_11 = calculate_coef(tuner_measure(MSS_FM, 1, 64));
745 /* set various audio level settings */
746 lv24020lp_write(AUDIO_CTRL1, TONE_LVL_SET(0) | VOL_LVL_SET(0));
747 lv24020lp_write_set(RADIO_CTRL2, AGCSP);
748 lv24020lp_write_set(RADIO_CTRL3, VOLSH);
749 lv24020lp_write(STEREO_CTRL, FMCS_SET(7) | AUTOSSR);
750 lv24020lp_write(PW_SCTRL, SS_CTRL_SET(3) | SM_CTRL_SET(1) |
751 PW_RAD);
753 tuner_status |= TUNER_AWAKE;
756 static int lp24020lp_tuned(void)
758 return RSS_FS(lv24020lp_read(RADIO_STAT)) < 0x1f;
761 static int lv24020lp_debug_info(int setting)
763 int val = -1;
765 if (setting >= LV24020LP_DEBUG_FIRST && setting <= LV24020LP_DEBUG_LAST)
767 val = 0;
769 if (tuner_awake())
771 switch (setting)
773 /* tuner-specific debug info */
774 case LV24020LP_CTRL_STAT:
775 val = lv24020lp_read(CTRL_STAT);
776 break;
778 case LV24020LP_REG_STAT:
779 val = lv24020lp_read(RADIO_STAT);
780 break;
782 case LV24020LP_MSS_FM:
783 val = tuner_measure(MSS_FM, 1, 16);
784 break;
786 case LV24020LP_MSS_IF:
787 val = tuner_measure(MSS_IF, 1000, 16);
788 break;
790 case LV24020LP_MSS_SD:
791 val = tuner_measure(MSS_SD, 1000, 16);
792 break;
794 case LV24020LP_IF_SET:
795 val = if_set;
796 break;
798 case LV24020LP_SD_SET:
799 val = sd_set;
800 break;
805 return val;
808 /** Public interfaces **/
809 void lv24020lp_init(void)
811 mutex_init(&tuner_mtx);
814 void lv24020lp_lock(void)
816 mutex_lock(&tuner_mtx);
819 void lv24020lp_unlock(void)
821 mutex_unlock(&tuner_mtx);
824 /* This function expects the driver to be locked externally */
825 void lv24020lp_power(bool status)
827 static const unsigned char tuner_defaults[][2] =
829 /* Block 1 writeable registers */
830 { MSRC_SEL, AFC_LVL },
831 { FM_OSC, 0x80 },
832 { SD_OSC, 0x80 },
833 { IF_OSC, 0x80 },
834 { CNT_CTRL, CNT1_CLR | SWP_CNT_L },
835 { IRQ_MSK, 0x00 }, /* IRQ_LVL -> Low to High */
836 { FM_CAP, 0x80 },
837 /* { IRQ_OUT, 0x00 }, No action on this register (skip) */
838 /* Block 2 writeable registers */
839 { RADIO_CTRL1, EN_AFC },
840 { IF_CENTER, 0x80 },
841 { IF_BW, 65*0x80 / 100 }, /* 65% of IF_OSC */
842 { RADIO_CTRL2, IF_PM_L },
843 { RADIO_CTRL3, AGC_SLVL | SE_FM },
844 { STEREO_CTRL, FMCS_SET(4) | AUTOSSR },
845 { AUDIO_CTRL1, TONE_LVL_SET(7) | VOL_LVL_SET(7) },
846 { AUDIO_CTRL2, BPFREQ_HIGH }, /* deemphasis 50us */
847 { PW_SCTRL, SS_CTRL_SET(3) | SM_CTRL_SET(3) | PW_RAD },
850 unsigned i;
852 if (status)
854 tuner_status |= (TUNER_PRESENCE_CHECKED | TUNER_POWERED);
856 /* if tuner is present, CHIP ID is 0x09 */
857 if (lv24020lp_read(CHIP_ID) == 0x09)
859 tuner_status |= TUNER_PRESENT;
861 /* After power-up, the LV2400x needs to be initialized as
862 follows: */
864 /* 1. Write default values to the registers: */
865 lv24020lp_regs[BLK_SEL] = 0; /* Force a switch on the first */
866 for (i = 0; i < ARRAYLEN(tuner_defaults); i++)
867 lv24020lp_write(tuner_defaults[i][0], tuner_defaults[i][1]);
869 /* Complete the startup calibration if the tuner is woken */
870 sleep(HZ/10);
873 else
875 /* Power off */
876 if (tuner_status & TUNER_PRESENT)
877 lv24020lp_write_clear(PW_SCTRL, PW_RAD);
879 tuner_status &= ~(TUNER_POWERED | TUNER_AWAKE);
883 int lv24020lp_set(int setting, int value)
885 int val = 1;
887 mutex_lock(&tuner_mtx);
889 switch(setting)
891 case RADIO_SLEEP:
892 set_sleep(value);
893 break;
895 case RADIO_FREQUENCY:
896 set_frequency(value);
897 break;
899 case RADIO_SCAN_FREQUENCY:
900 /* TODO: really implement this */
901 set_frequency(value);
902 val = lp24020lp_tuned();
903 break;
905 case RADIO_MUTE:
906 if (value)
907 lv24020lp_write_clear(RADIO_CTRL3, AMUTE_L);
908 else
909 lv24020lp_write_set(RADIO_CTRL3, AMUTE_L);
910 break;
912 case RADIO_REGION:
913 if (lv24020lp_region_data[value])
914 lv24020lp_write_set(AUDIO_CTRL2, DEEMP);
915 else
916 lv24020lp_write_clear(AUDIO_CTRL2, DEEMP);
917 break;
919 case RADIO_FORCE_MONO:
920 if (value)
921 lv24020lp_write_set(STEREO_CTRL, ST_M);
922 else
923 lv24020lp_write_clear(STEREO_CTRL, ST_M);
924 break;
926 default:
927 value = -1;
930 mutex_unlock(&tuner_mtx);
932 return val;
935 int lv24020lp_get(int setting)
937 int val = -1;
939 mutex_lock(&tuner_mtx);
941 switch(setting)
943 case RADIO_TUNED:
944 /* TODO: really implement this */
945 val = lp24020lp_tuned();
946 break;
948 case RADIO_STEREO:
949 val = (lv24020lp_read(RADIO_STAT) & RSS_MS) != 0;
950 break;
952 case RADIO_PRESENT:
954 bool fmstatus = true;
956 if (!(tuner_status & TUNER_PRESENCE_CHECKED))
957 fmstatus = tuner_power(true);
959 val = (tuner_status & TUNER_PRESENT) != 0;
961 if (!fmstatus)
962 tuner_power(false);
963 break;
966 default:
967 val = lv24020lp_debug_info(setting);
970 mutex_unlock(&tuner_mtx);
972 return val;
974 #endif /* BOOTLOADER */