summaryrefslogtreecommitdiff
path: root/firmware/drivers/tuner/s1a0903x01.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/tuner/s1a0903x01.c')
-rw-r--r--firmware/drivers/tuner/s1a0903x01.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/firmware/drivers/tuner/s1a0903x01.c b/firmware/drivers/tuner/s1a0903x01.c
new file mode 100644
index 0000000000..cdeba2b3b4
--- /dev/null
+++ b/firmware/drivers/tuner/s1a0903x01.c
@@ -0,0 +1,172 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 * Tuner "middleware" for Samsung S1A0903X01 chip
10 *
11 * Copyright (C) 2003 Linus Nielsen Feltzing
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 "kernel.h"
25#include "tuner.h" /* tuner abstraction interface */
26#include "fmradio.h" /* physical interface driver */
27#include "mpeg.h"
28#include "sound.h"
29
30#define DEFAULT_IN1 0x100003 /* Mute */
31#define DEFAULT_IN2 0x140884 /* 5kHz, 7.2MHz crystal */
32#define PLL_FREQ_STEP 10000
33
34static int fm_in1;
35static int fm_in2;
36static int fm_present = -1; /* unknown */
37
38/* tuner abstraction layer: set something to the tuner */
39int s1a0903x01_set(int setting, int value)
40{
41 int val = 1;
42
43 switch(setting)
44 {
45 case RADIO_SLEEP:
46 if (!value)
47 { /* wakeup: just unit */
48 fm_in1 = DEFAULT_IN1;
49 fm_in2 = DEFAULT_IN2;
50 fmradio_set(1, fm_in1);
51 fmradio_set(2, fm_in2);
52 }
53 /* else we have no sleep mode? */
54 break;
55
56 case RADIO_FREQUENCY:
57 {
58 int pll_cnt;
59#if CONFIG_CODEC == MAS3587F
60 /* Shift the MAS internal clock away for certain frequencies to
61 * avoid interference. */
62 int pitch = 1000;
63
64 /* 4th harmonic falls in the FM frequency range */
65 int if_freq = 4 * mpeg_get_mas_pllfreq();
66
67 /* shift the mas harmonic >= 300 kHz away using the direction
68 * which needs less shifting. */
69 if (value < if_freq)
70 {
71 if (if_freq - value < 300000)
72 pitch = 1003 - (if_freq - value) / 100000;
73 }
74 else
75 {
76 if (value - if_freq < 300000)
77 pitch = 997 + (value - if_freq) / 100000;
78 }
79 sound_set_pitch(pitch);
80#endif
81 /* We add the standard Intermediate Frequency 10.7MHz
82 ** before calculating the divisor
83 ** The reference frequency is set to 50kHz, and the VCO
84 ** output is prescaled by 2.
85 */
86
87 pll_cnt = (value + 10700000) / (PLL_FREQ_STEP/2) / 2;
88
89 /* 0x100000 == FM mode
90 ** 0x000002 == Microprocessor controlled Mute
91 */
92 fm_in1 = (fm_in1 & 0xfff00007) | (pll_cnt << 3);
93 fmradio_set(1, fm_in1);
94 break;
95 }
96
97 case RADIO_SCAN_FREQUENCY:
98 /* Tune in and delay */
99 s1a0903x01_set(RADIO_FREQUENCY, value);
100 sleep(1);
101 /* Start IF measurement */
102 fm_in1 |= 4;
103 fmradio_set(1, fm_in1);
104 sleep(1);
105 val = s1a0903x01_get(RADIO_TUNED);
106 break;
107
108 case RADIO_MUTE:
109 fm_in1 = (fm_in1 & 0xfffffffe) | (value?1:0);
110 fmradio_set(1, fm_in1);
111 break;
112
113 case RADIO_FORCE_MONO:
114 fm_in2 = (fm_in2 & 0xfffffffb) | (value?0:4);
115 fmradio_set(2, fm_in2);
116 break;
117 /* NOTE: These were only zeroed when starting the tuner from OFF
118 but the default values already set them to 0. */
119#if 0
120 case S1A0903X01_IF_MEASUREMENT:
121 fm_in1 = (fm_in1 & 0xfffffffb) | (value?4:0);
122 fmradio_set(1, fm_in1);
123 break;
124
125 case S1A0903X01_SENSITIVITY:
126 fm_in2 = (fm_in2 & 0xffff9fff) | ((value & 3) << 13);
127 fmradio_set(2, fm_in2);
128 break;
129#endif
130 default:
131 val = -1;
132 }
133
134 return val;
135}
136
137/* tuner abstraction layer: read something from the tuner */
138int s1a0903x01_get(int setting)
139{
140 int val = -1;
141 switch(setting)
142 {
143 case RADIO_PRESENT:
144 if (fm_present == -1)
145 {
146#ifdef HAVE_TUNER_PWR_CTRL
147 bool fmstatus = tuner_power(true);
148#endif
149 /* 5kHz, 7.2MHz crystal, test mode 1 */
150 fmradio_set(2, 0x140885);
151 fm_present = (fmradio_read(0) == 0x140885);
152#ifdef HAVE_TUNER_PWR_CTRL
153 if (!fmstatus)
154 tuner_power(false);
155#endif
156 }
157
158 val = fm_present;
159 break;
160
161 case RADIO_TUNED:
162 val = fmradio_read(3);
163 val = abs(10700 - ((val & 0x7ffff) / 8)) < 50; /* convert to kHz */
164 break;
165
166 case RADIO_STEREO:
167 val = fmradio_read(3);
168 val = ((val & 0x100000) ? true : false);
169 break;
170 }
171 return val;
172}