xref: /haiku/src/add-ons/media/media-add-ons/radeon/Tuner.cpp (revision ffec4cb14d0b87745137bcb115e949f1fbc895b9)
1 /******************************************************************************
2 /
3 /	File:			Tuner.cpp
4 /
5 /	Description:	Philips Desktop TV Tuners interface.
6 /
7 /	Copyright 2001, Carlos Hasan
8 /
9 *******************************************************************************/
10 
11 #include <Debug.h>
12 #include "Tuner.h"
13 
14 enum tuner_control_bits {
15     CHANGE_PUMP             = 0x40,     /* change pump settings */
16     CHANGE_PUMP_FAST        = 0x00,     /*  for fast tuning */
17     CHANGE_PUMP_SLOW        = 0x40,     /*  for moderate speed tuning */
18 
19     TEST_MODE               = 0x38,     /* test mode settings */
20     TEST_MODE_NORMAL        = 0x08,     /*  for normal operation */
21 
22     RATIO_SELECT            = 0x06,     /* ratio select */
23     RATIO_SELECT_FAST       = 0x00,     /*  fast picture search */
24     RATIO_SELECT_SLOW       = 0x02,     /*  slow picture search */
25     RATIO_SELECT_NORMAL     = 0x06,     /*  normal picture search */
26 
27     OS_MODE                 = 0x01,     /* PLL disabling */
28     OS_MODE_NORMAL          = 0x00,     /*  for normal operation */
29     OS_MODE_SWITCH          = 0x01      /*  change pump to high impedance */
30 };
31 
32 enum tuner_status_bits {
33     STB_POR                 = 0x80,     /* power on reset */
34     STB_FL                  = 0x40,     /* in-lock flag */
35     STB_INF                 = 0x38,     /* digital information */
36     STB_ADC                 = 0x07      /* A/D converter */
37 };
38 
39 /*****************************************************************************
40 /
41 /   Tuner Parameters and Frequencies for TV Antenna and Cable Channels
42 /
43 ******************************************************************************/
44 
45 static const int kBandsPerTuner   = 5;
46 
47 static const struct {
48     tuner_type brand;
49     const char* name;
50     struct {
51         int pll;
52         float minFrequency, maxFrequency;
53     } bands[kBandsPerTuner];
54 } kTunerTable[] = {
55     /* Philips FI1236 NTSC M/N */
56     { C_TUNER_FI1236, "FI1236 NTSC",
57       { { 0xa2,  54.00, 157.25 },
58         { 0x94, 162.00, 451.25 },
59         { 0x34, 451.25, 463.25 },
60         { 0x31, 463.25, 801.25 },
61         { 0x00,   0.00,   0.00 } } },
62 
63     /* Philips FI1236J NTSC Japan */
64     { C_TUNER_FI1236J, "FI1236J NTSC Japan",
65       { { 0xa2,  54.00, 157.25 },
66         { 0x94, 162.00, 451.25 },
67         { 0x34, 451.25, 463.25 },
68         { 0x31, 463.25, 801.25 },
69         { 0x00,   0.00,   0.00 } } },
70 
71     /* Philips FI1236MK2 NTSC M/N */
72     { C_TUNER_FI1236MK2, "FI1236MK2 NTSC",
73       { { 0xa0,  55.25, 160.00 },
74         { 0x90, 160.00, 454.00 },
75         { 0x30, 454.00, 855.25 },
76         { 0x00,   0.00,   0.00 },
77         { 0x00,   0.00,   0.00 } } },
78 
79     /* Philips FI1216 PAL B/G */
80     { C_TUNER_FI1216, "FI1216 PAL",
81       { { 0xa2,  45.00, 140.25 },
82         { 0xa4, 140.25, 168.25 },
83         { 0x94, 168.25, 447.25 },
84         { 0x34, 447.25, 463.25 },
85         { 0x31, 463.25, 855.25 } } },
86 
87     /* Philips FI1216MK2 PAL B/G */
88     { C_TUNER_FI1216MK2, "FI1216MK2 PAL",
89       { { 0xa0,  48.25, 170.00 },
90         { 0x90, 170.00, 450.00 },
91         { 0x30, 450.00, 855.25 },
92         { 0x00,   0.00,   0.00 },
93         { 0x00,   0.00,   0.00 } } },
94 
95     /* Philips FI1216MF PAL B/G, SECAM L/L' */
96     { C_TUNER_FI1216MF, "FI1216MF PAL/SECAM",
97       { { 0xa1,  45.00, 168.25 },
98         { 0x91, 168.25, 447.25 },
99         { 0x31, 447.25, 855.25 },
100         { 0x00,   0.00,   0.00 },
101         { 0x00,   0.00,   0.00 } } },
102 
103     /* Philips FI1246 PAL I */
104     { C_TUNER_FI1246, "FI1246 PAL I",
105       { { 0xa2,  45.00, 140.25 },
106         { 0xa4, 140.25, 168.25 },
107         { 0x94, 168.25, 447.25 },
108         { 0x34, 447.25, 463.25 },
109         { 0x31, 463.25, 855.25 } } },
110 
111     /* Philips FI1256 SECAM D/K */
112     { C_TUNER_FI1256, "FI1256 SECAM",
113       { { 0xa0,  48.25, 168.25 },
114         { 0x90, 175.25, 455.25 },
115         { 0x30, 463.25, 863.25 },
116         { 0x00,   0.00,   0.00 },
117         { 0x00,   0.00,   0.00 } } },
118 
119     /* Temic FN5AL PAL I/B/G/DK, SECAM DK */
120     { C_TUNER_TEMIC_FN5AL_PAL, "Temic FN5AL PAL",
121       { { 0xa2,  45.00, 140.25 },
122         { 0xa4, 140.25, 168.25 },
123         { 0x94, 168.25, 447.25 },
124         { 0x31, 447.25, 855.25 },
125         { 0x00,   0.00,   0.00 } } },
126 
127     /* Temic FN5AL PAL I/B/G/DK, SECAM DK */
128     { C_TUNER_TEMIC_FN5AL_SECAM, "Temic FN5AL SECAM",
129       { { 0xa0,  48.25, 168.25 },
130         { 0x90, 175.25, 455.25 },
131         { 0x30, 463.25, 863.25 },
132         { 0x00,   0.00,   0.00 },
133         { 0x00,   0.00,   0.00 } } } };
134 
135 static const int kNumTuners = sizeof(kTunerTable) / sizeof(kTunerTable[0]);
136 
137 
CTuner(CI2CPort & port)138 CTuner::CTuner(CI2CPort & port)
139 	:	fPort(port),
140 		fType(C_TUNER_NONE),
141 		fAddress(0xC6),
142 		fDivider(0)
143 {
144 	PRINT(("CTuner::CTuner()\n"));
145 
146 	if( fPort.InitCheck() == B_OK ) {
147 		radeon_video_tuner tuner;
148 		radeon_video_decoder video;
149 		radeon_video_clock clock;
150 		int dummy;
151 
152 		fPort.Radeon().GetMMParameters(tuner, video, clock, dummy, dummy, dummy);
153 		switch (tuner) {
154 		case C_RADEON_NO_TUNER:
155 			fType = C_TUNER_NONE;
156 			break;
157 		case C_RADEON_FI1236_MK1_NTSC:
158 			fType = C_TUNER_FI1236;
159 			break;
160 		case C_RADEON_FI1236_MK2_NTSC_JAPAN:
161 			fType = C_TUNER_FI1236J;
162 			break;
163 		case C_RADEON_FI1216_MK2_PAL_BG:
164 			fType = C_TUNER_FI1216;
165 			break;
166 		case C_RADEON_FI1246_MK2_PAL_I:
167 			fType = C_TUNER_FI1246;
168 			break;
169 		case C_RADEON_FI1216_MF_MK2_PAL_BG_SECAM_L:
170 			fType = C_TUNER_FI1216MF;
171 			break;
172 		case C_RADEON_FI1236_MK2_NTSC:
173 			fType = C_TUNER_FI1236MK2;
174 			break;
175 		case C_RADEON_FI1256_MK2_SECAM_DK:
176 			fType = C_TUNER_FI1256;
177 			break;
178 		case C_RADEON_FI1216_MK2_PAL_BG_SECAM_L:
179 			fType = C_TUNER_FI1216MK2;
180 			break;
181 		case C_RADEON_TEMIC_FN5AL_PAL_IBGDK_SECAM_DK:
182 			fType = C_TUNER_TEMIC_FN5AL_PAL;
183 			break;
184 		default:
185 			fType = C_TUNER_FI1236;
186 			break;
187 		}
188 
189 	    for (fAddress = 0xc0; fAddress <= 0xc6; fAddress += 0x02) {
190 	        if (fPort.Probe(fAddress)) {
191 	        	PRINT(("CTuner::CTuner() - TV Tuner found at I2C port 0x%02x\n", fAddress));
192 				break;
193 			}
194 	    }
195 	}
196 	if( InitCheck() != B_OK )
197 		PRINT(("CTuner::CTuner() - TV Tuner not found!\n"));
198 }
199 
~CTuner()200 CTuner::~CTuner()
201 {
202 	PRINT(("CTuner::~CTuner()\n"));
203 }
204 
InitCheck() const205 status_t CTuner::InitCheck() const
206 {
207     return (fType != C_TUNER_NONE && fAddress >= 0xc0 && fAddress <= 0xc6) ?
208     	B_OK : B_ERROR;
209 }
210 
SetFrequency(float frequency,float picture)211 bool CTuner::SetFrequency(float frequency, float picture)
212 {
213 	//PRINT(("CTuner::SetFrequency(%g, %g)\n", frequency, picture));
214 
215     for (int index = 0; index < kNumTuners; index++) {
216         if (kTunerTable[index].brand == fType) {
217             for (int band = 0; band < kBandsPerTuner; band++) {
218                 if (frequency >= kTunerTable[index].bands[band].minFrequency &&
219                     frequency <= kTunerTable[index].bands[band].maxFrequency) {
220                     SetParameters(
221                         (int) (16.0 * (frequency + picture)),
222                         CHANGE_PUMP_FAST | RATIO_SELECT_NORMAL |
223                         TEST_MODE_NORMAL | OS_MODE_NORMAL,
224                         kTunerTable[index].bands[band].pll |
225                         ((Status() & STB_INF) >> 3));
226                     return true;
227                 }
228             }
229         }
230     }
231     return false;
232 }
233 
SweepFrequency(float frequency,float picture)234 bool CTuner::SweepFrequency(float frequency, float picture)
235 {
236 	PRINT(("CTuner::SweepFrequency(%g, %g)\n", frequency, picture));
237 
238     float centerFrequency = frequency;
239 
240     /* sweeping down */
241     do {
242         SetFrequency(frequency, picture);
243         for (int timeout = 0; timeout < 10; timeout++) {
244             snooze(20000);
245             if (IsLocked())
246                 break;
247 	    }
248     } while (ADC() == 0  &&
249              (frequency -= 0.5000) > centerFrequency - 3.000);
250 
251     /* sweeping up */
252     do {
253         SetFrequency(frequency, picture);
254         for (int timeout = 0; timeout < 10; timeout++) {
255             snooze(20000);
256             if (IsLocked())
257                 break;
258         }
259     } while (ADC() != 0 &&
260              (frequency += 0.0625) < centerFrequency + 0.500);
261 
262     return (ADC() == 0);
263 }
264 
Name() const265 const char * CTuner::Name() const
266 {
267     for (int index = 0; index < kNumTuners; index++) {
268         if (kTunerTable[index].brand == fType)
269             return kTunerTable[index].name;
270     }
271     return 0;
272 }
273 
Type() const274 tuner_type CTuner::Type() const
275 {
276 	return fType;
277 }
278 
HasSignal(void)279 bool CTuner::HasSignal(void)
280 {
281     return (IsLocked() && ADC() <= 2);
282 }
283 
Status(void)284 int CTuner::Status(void)
285 {
286     char buffer[1];
287     fPort.Read(fAddress, buffer, sizeof(buffer));
288     return buffer[0] & 0xff;
289 }
290 
ADC(void)291 int CTuner::ADC(void)
292 {
293     return Status() & STB_ADC;
294 }
295 
IsLocked(void)296 bool CTuner::IsLocked(void)
297 {
298     return (Status() & STB_FL) != 0;
299 }
300 
SetParameters(int divider,int control,int band)301 void CTuner::SetParameters(int divider, int control, int band)
302 {
303     char buffer[4];
304 
305     if (divider > fDivider) {
306         buffer[0] = (divider >> 8) & 0x7f;
307         buffer[1] = (divider >> 0) & 0xff;
308 
309         buffer[2] = (control | 0x80);
310         buffer[3] = (band & 0xff);
311     }
312     else {
313         buffer[0] = (control | 0x80);
314         buffer[1] = (band & 0xff);
315 
316         buffer[2] = (divider >> 8) & 0x7f;
317         buffer[3] = (divider >> 0) & 0xff;
318     }
319 
320     fDivider = divider;
321 
322     fPort.Write(fAddress, buffer, sizeof(buffer));
323 }
324